Custom Test Asserts in Planck
The cljs.test
library provides a mechanism for writing custom asserts that can be used with the is
macro—in the form of an assert-expr
defmulti
.
In JVM ClojureScript, any assert-expr
defmethod
must be written in Clojure, and you must arrange to have this Clojure code executed when running tests. This is a fallout of the fact that is
is a macro written in Clojure.
But, in the bootstrapped ClojureScript port of cljs.test
that ships with Planck 1.10, such defmethod
s can be written directly in ClojureScript (even in the REPL if you wish!) This, IMHO, makes things a bit more straightforward.
Here's an example.
Fire up the Planck REPL, passing the -s
flag so that static functions are used (this is needed to cope with the underlying JavaScript generated). Issue a require
to load the cljs.test
library:
(require '[cljs.test :refer-macros [is]])
For our example, lets focus on the char?
predicate. In ClojureScript, if you pass nil
to char?
, it will throw an exception (as opposed to returning false
).
If you evaluate (is (char? nil))
, you will see the consequence of this in the actual
portion of the report, which unfortunately could be misleading:
ERROR in () (isUnicodeChar@file:269:12)
expected: (char? nil)
actual: #object[TypeError TypeError: null is not an object (evaluating 'ch.length')]
Let's improve this by writing a specialized assertion for char?
:
(defmethod cljs.test/assert-expr 'char?
[menv msg form]
(let [arg (second form)
result (and (not (nil? arg))
(char? arg))]
`(do
(if ~result
(cljs.test/do-report
{:type :pass
:message ~msg
:expected '~form
:actual (list '~'char? ~arg)})
(cljs.test/do-report
{:type :fail
:message ~msg
:expected '~form
:actual (list '~'not
(list '~'char? ~arg))}))
~result)))
The above is a lot like the general predicate assertion built into cljs.test
, but it also includes a nil
-check prior to applying char?
.
With this defmethod
having been evaluated at the Planck REPL, now (is (char? nil))
genreates a nicer error report:
FAIL in () (eval@[native code]:NaN:NaN)
expected: (char? nil)
actual: (not (char? nil))