A Short Midje Crash Course
Here’s a Midje fact:
(fact "adding two and two produces four" (+ 2 2) => 4)
Midje introduces the =>
(which I read produces): the expression to the left
of =>
is evaluated and compared with the expression on its right, using
Midje’s notion of extended equality. The extended part is useful to us here:
(fact "adding two and two produces a positive number" (+ 2 2) => pos?)
If the result of the right side is a function, it is applied to the result of
the left side to see if the test passes. In this case (pos? (+ 2 2))
is
true, so the test passes.
So why not write (pos? (+ 2 2)) => true
? There is a difference in what is
printed when the test fails: the first prints this:
Actual result did not agree with the checking function. Actual result: -98 Checking function: pos?
while the second prints:
Expected: true Actual: false
The first form helps us out because it gives us more information about what happened when a test fails.
Testing Deep Structures
In Avi, the editor’s state is a large, nested map containing open buffers, the cursor position, the current viewport position, the contents of the status line, the editor’s mode and more.
Each time an event (usually a keystroke) is received, the editor state is
advanced to the next state. For example, the editor might have a key :mode
with a value of :normal
, but after advancing the state by applying the ":"
character, :mode
might be :command-line
.
The usual way to test this might be:
(fact "`:` enters command-line mode" (:mode (editor :after ":")) => :command-line)
(editor
is a testing helper function which allows super-concise tests.)
If this test fails, we’ll see:
FAIL "`:` enters command-line mode" Expected: :command-line Actual: :normal
This doesn’t tell us much, does it? On the other hand, we can write a mode
testing function:
(defn mode [expected-mode] (fn [editor] (= (:mode editor) expected-mode)))
and rewrite our fact:
(fact "`:` enters command-line mode" (editor :after ":") => (mode :command-line))
Now, when the test fails, we might be able to see, for example, that a ":" was literally inserted into the buffer–or that it wasn’t.
A General Rule
I think this warrants a general rule:
When you find yourself doing gyrations on the left side of
=>
, write a Midje checker instead.
It’s also possible that you could be testing through a different function which produces a "more-inner" data structure – but first consider whether that function’s signature is stable enough, or you will cause yourself pain later.