Great Expectations
Published 2015-04-14 @ 12:00
Tagged minitest
minitest/spec
has existed since v1.3.0 (6.5 years). It started as a
simple proof of concept to show that there was a 1:1 mapping between
“spec-style” and “unit-style” tests (not to be confused with BDD vs
TDD, which is a development process). It showed (in 67 lines!), that
every describe
was just a Test subclass, and every it
was just a
test method (with strange inheritance).
minitest/spec
has only grown to 152 lines since then but it really
hasn’t changed all that much. Until yesterday.
The older spec system relied on a thread-local variable in order to understand what the current test method was. It was a limitation of how you called the expectation methods. So, when you wrote a test like this:
we call must_equal
on the result of 1+1
. This implies that the
method is on Object in order to be called on the value 2
. In order
to map must_equal
back to Minitest::Test
’s assert_equal
,
minitest needed to know what test the expectation was in and that was
done via Minitest::Spec.current
, which just accesses a thread-local
variable. That works great 99.9% of the time, until, you know, you use
threads in your tests. (Why you would use threads inside your tests is
irrelevant.)
So, if your test changed to this:
1 2 3 4 5 6 7 |
describe Something do it "should blah-blah threaded" do my_threaded_test_thingy do (1+1).must_equal 2 end end end |
then it would blow up, because you’d be wrapping must_equal
in your
own thread and that would make the thread-local variable unavailable
(they’re not scoped to parent threads, for better or worse).
Yesterday’s release of 5.6 brings new expect system from tenderlove
that adds a struct and one new method _
. The method wraps the
resultant value in a Expectation value monad. All in all, it only adds
11 lines of code to minitest. All of the usual expectation methods are
defined, but this time around, they know what test they’re in because
it was stored off when the monad was created.
So, one character change later, and the following works:
1 2 3 4 5 6 7 |
describe Something do it "should blah-blah threaded" do my_threaded_test_thingy do _(1+1).must_equal 2 end end end |
The method _
is also aliased to value
if you prefer verbier tests.
It is also aliased to expect
, to make transitioning easier, but
<bikeshed>1I really dislike that name</bikeshed> because it is
non-descriptive. value
is much better, and imo, _
is even better
because it gets out of your way and lets you focus on the actual meat
of the test.
At some point (pre-6.0) the old expectations are going to be deprecated in favor of the new system. Until then, they’re fine to use and won’t make any noise until the deprecation is officially planned. That will remove the monkeypatches on Object for all of the expectations that minitest supports. Hopefully that’ll reclaim the 11 lines we added.
Apologies are owed to Dickens. I couldn’t help myself, even tho I hated that book.
-
<bikeshed> means: don’t argue with me about it. I don’t care to argue about it. ↩