Minitest in spec style
describe and it
Minitest ships two front ends. Minitest::Test is the class style of lesson 149; describe and it are the spec style, which reads as a sentence and groups tests by behaviour:
require "minitest/autorun"
require_relative "../lib/calculator"
describe Calculator do
it "adds" do
_(Calculator.new.add(2, 2)).must_equal 4
end
it "raises on zero" do
_(-> { Calculator.new.divide(1, 0) }).must_raise ArgumentError
end
end
Under the hood it is the same runner: each it becomes a test method, and the description becomes part of the name in the report. The style changes how the file reads, not what runs.
let
let defines a memoised helper: the block runs the first time the name is used in each test, and the value is fresh for the next one:
describe Calculator do
let(:calc) { Calculator.new }
it "adds" do
_(calc.add(2, 2)).must_equal 4
end
end
A test that never mentions calc never builds it, which is the advantage over setup and the reason a spec file with many let lines stays fast.
Expectations
An expectation wraps the value in _() and calls a matcher. The names read as a sentence and the failure message names the matcher:
| Expectation | Asserts |
|---|---|
| _(x).must_equal 4 | equal to 4 |
| _(x).must_be_nil | nil |
| _(x).must_be :empty? | the predicate is true |
| _(x).wont_be_empty | the negation |
| _(-> { f }).must_raise E | the block raises E |
wont_* is the negation family. A lambda is needed for must_raise because the call has to be lazy: an expression would raise before the matcher saw it.
Choosing a style
Both styles run in one project, and a suite with both is harder to read than either. Pick one per project:
- Class style. One class, one test class, explicit names: good for a library with a small public surface.
- Spec style. Grouped by behaviour, descriptions read as sentences: good for a project where the tests document the API.
The course uses the class style for library tests and the spec style here because RSpec in lesson 153, later, uses the same words. Mixing the two in one folder is the only choice that is clearly wrong.
What to watch for
must_equal on an object compares with
==; a class without ==
compares identity, and two equal-looking objects fail. Lesson 87 has the
rule and lesson 113 the value object that fixes it.
A describe block with one test and five
let lines is a sign the setup is too broad. Narrow
the test until it needs one or two helpers.
Next: Doubles and stubs
Article author: Arthur Isaev