Getting a test to fail is one thing; getting it to express why it failed is another.
Clojure.test provides an assertion macro: is
(deftest “my-function”
(testing “some requirement”
(is (something-that-evaluates-to-bool (arg1) (arg2))
“Message to print when it’s false”)))
When this assertion fails, in addition to the message, “expected” and “actual” results print. The is macro tries to be a little clever.
If the expression passed to is an S-expr, and the first element of the is recognized as a function. Then is prints that first symbol directly, then evaluates all the arguments to the function and prints the results. For instance:
expected: (function-name (arg1) (arg2))
actual: (not (function-name “1st arg value” “2nd arg value”))
However, if is does not recognize that first element as a function, the whole expression passed to is is evaluated for the actual, and you get:
expected: (something-that-evaluates-to-bool (arg1) (arg2))
actual: false
To get the more communicative output, write a function with a name that describes the property you’re testing. A top-level defn will be recognized by is as a function, so declare your test function that way.
For instance, if I’m testing whether a vector of numbers is sorted, I could use built-in functions:
(let [v [1 3 2 4]]
(is (apply <= v) “not sorted”))
Then I see[1]:
expected: (apply <= v)
actual: (not
(apply
#
[1 3 2 4]))
Printing a function is never pretty. If, instead, I give the desired property a name:
(defn ascending? [v] (apply <= v))
(let [v [1 3 2 4]]
(is (ascending? v) “not sorted”))
Then I get something much more communicative:
expected: (ascending? v)
actual: (not (ascending? [1 3 2 4]))
There it is — declarative test output through creation of simple functions.
Bonus: If you want to make your failure output even better, define special functionality just for your function, as @pjstadig did for =.
—————–
[1] I’m using humane-test-output to get the “actual” pretty-printed.
Clojure