Minitest provides a complete suite of testing facilities supporting TDD, BDD, mocking, and benchmarking.
minitest/test is a small and incredibly fast unit testing framework. It provides a rich set of assertions to make your tests clean and readable.
minitest/spec is a functionally complete spec engine. It hooks onto minitest/test and seamlessly bridges test assertions over to spec expectations.
minitest/benchmark is an awesome way to assert the performance of your algorithms in a repeatable manner. Now you can assert that your newb co-worker doesn’t replace your linear algorithm with an exponential one!
minitest/mock by Steven Baker, is a beautifully tiny mock (and stub) object framework.
minitest/pride shows pride in testing and adds coloring to your test output
minitest/test_task – a full-featured and clean rake task generator.
– Minitest Github
โฆ๏ธ Incredibly small and fast runner, but no bells and whistles.
Let’s take the given example in the doc, we’d like to test the following class:
class Meme
def i_can_has_cheezburger?
"OHAI!"
end
def will_it_blend?
"YES!"
end
end
๐งช Unit tests
Define your tests as methods beginning with test_.
require "minitest/autorun"
class TestMeme < Minitest::Test
def setup
@meme = Meme.new
end
def test_that_kitty_can_eat
assert_equal "OHAI!", @meme.i_can_has_cheezburger?
end
def test_that_it_will_not_blend
refute_match /^no/i, @meme.will_it_blend?
end
def test_that_will_be_skipped
skip "test this later"
end
end
# File lib/minitest/test.rb, line 153
def setup; end
โฆ๏ธ Runs before every test. Use this to set up before each test run.
The terms “unit test” and “spec” are often used in software testing, and while they can overlap, they have some key differences:
๐งช Unit Test vs ๐ Spec: Key Differences
๐ฌUnit Test
- Purpose: Tests a single unit of code (typically a method, function, or class) in isolation
- Scope: Very focused and narrow – tests one specific piece of functionality
- Style: Usually follows a more traditional testing approach with setup, execution, and assertion
- Framework examples: Minitest (like in your Ruby file), JUnit, pytest
- Structure: Often uses
test_prefix orTestclasses with assertion methods
๐ Spec (Specification)
- Purpose: Describes the behavior and requirements of the system in a more readable, documentation-like format
- Scope: Can cover unit-level, integration, or acceptance testing
- Style: Uses natural language descriptions that read like specifications
- Framework examples: RSpec, Jasmine, Mocha, Jest
- Structure: Uses descriptive blocks like
describe,it,should
โ๏ธ Key Differences
1. โ๏ธ Writing Style:
- Unit Test:
def test_array_is_empty with assertions - Spec:
describe "when array is empty" do
it "should return error message"
2. ๐๏ธ Readability:
- Unit Test: More code-focused, technical
- Spec: More human-readable, business-focused
3. ๐ฏ Philosophy:
- Unit Test: Test the implementation
- Spec: Specify the behavior (BDD – Behavior Driven Development)
๐ Example Comparison
๐ท๏ธ Our current Minitest code:
def array_is_an_empty_array
assert_equal 'Provide an array with length 2 or more', two_sum([], 9)
end
๐จ RSpec equivalent (spec style):
describe "two_sum" do
context "when array is empty" do
it "returns an error message" do
expect(two_sum([], 9)).to eq('Provide an array with length 2 or more')
end
end
end
Both test the same functionality, but specs emphasize describing behavior in natural language, making them easier for non-technical stakeholders to understand. ๐
๐ฌ Mini-test equivalent:
# frozen_string_literal: true
require 'minitest/spec'
require_relative 'two_sum'
describe "TwoSum" do
describe "when array is empty" do
it "returns an error message" do
_(two_sum([], 9)).must_equal 'Provide an array with length 2 or more'
end
end
end
The underscore _() in Minitest spec style is a wrapper method that converts the value into an expectation object.
Here’s why it’s used:
๐ Why the Underscore _()?
๐ฏ Purpose:
The _() method wraps your actual value and returns a special expectation object that has assertion methods like must_equal, must_be, etc.
โ๏ธ How it works:
# This:
_(two_sum([], 9)).must_equal 'Provide an array with length 2 or more'
# Is equivalent to:
# 1. two_sum([], 9) returns some value
# 2. _() wraps that value into an expectation object
# 3. .must_equal() is called on that expectation object
๐ Alternative Syntaxes
1. ๐ Using expect() (more readable):
expect(two_sum([], 9)).must_equal 'Provide an array with length 2 or more'
2. ๐ง Using value() (explicit):
value(two_sum([], 9)).must_equal 'Provide an array with length 2 or more'
3. ๐ท๏ธ Traditional unit test style (no wrapper needed):
assert_equal 'Provide an array with length 2 or more', two_sum([], 9)
๐ก Why underscore specifically?
- Minimal syntax:
_()is short and doesn’t clutter the code - Ruby convention: Underscore often indicates “throwaway” or “utility” variables
- Non-conflicting: Unlikely to conflict with your method names
- Chainable: Creates a fluent interface for assertions
๐จ Complete comparison:
# Spec style with underscore
_(result).must_equal expected
# Spec style with expect (more readable)
expect(result).must_equal expected
# Unit test style (no wrapper)
assert_equal expected, result
The expect() version is often preferred because it’s more self-documenting!
๐จ Alternative Spec Style with Expectation Syntax:
# frozen_string_literal: true
require 'minitest/spec'
require_relative 'two_sum'
describe "TwoSum" do
describe "when array is empty" do
it "returns an error message" do
expect(two_sum([], 9)).must_equal 'Provide an array with length 2 or more'
end
end
end
โ๏ธ Key Differences in Minitest
๐ง Setup Required:
- Unit Test:
require 'minitest/test' - Spec:
require 'minitest/spec'
โ๏ธ Assertion Style:
- Unit Test:
assert_equal expected, actual - Spec:
_(actual).must_equal expected or expect(actual).must_equal expected
๐๏ธ Structure:
- Unit Test: Classes with test_ methods
- Spec: describe blocks with it blocks
๐ฏ Readability:
Both styles work with Minitest, but the spec style reads more like natural language documentation, making it easier to understand the intended behavior!
Excellent question! Let me clarify the relationship between TDD/BDD (methodologies) and RSpec/Minitest (testing frameworks):
Happy Testing!