[plumula/mimolette "0.2.1"] ;; latest release
Check your specs from clojure.test
and
cljs.test
.
Here we check a-function
and another-function
against their specs:
(ns whatever.my-test
(:require [whatever.my :refer [a-function another-function]] ; The functions we’re going to test
[whatever.my.spec] ; The specs for our functions are
; in another namespace, load them
[plumula.mimolette.alpha :refer [defspec-test]])) ; Use the `alpha` version for recent
; releases of spec
(defspec-test test-foo-spec `[a-function another-function]) ; Test `a-function` and `another-function`
; againts their respective specs and name
; the test `test-foo-spec`
Mimolette works with Clojure 1.9.0-alpha8
and upwards, and ClojureScript
1.9.183
and upwards. This is because it relies on the spec.test/abbrev-result
function.
For Clojure versions 1.9.alpha-8
to 1.9.alpha-15
and ClojureScript version
1.9.183
to 1.9.521
, you need to require mimolette’s non-alpha
namespace.
(ns whatever.my-test
(:require [plumula.mimolette :refer [defspec-test]]))
Starting from Clojure 1.9.alpha-16
and ClojureScript 1.9.542
, you need to
require mimolette’s alpha
namespace.
(ns whatever.my-test
(:require [plumula.mimolette.alpha :refer [defspec-test]]))
This is a consequence of the Clojure team adding an alpha
suffix
to spec’s namespaces.
In your test namespace, require Mimolette – choosing either the alpha
- or the
non-alpha
- namespace depending on your version
of Clojure(Script). Mimolette works both for Clojure and ClojureScript.
You’re now ready to test your functions against their specs.
(defspec-test test-foo-spec `[a-function another-function])
The functions-to-be-tested must be named by fully-qualified symbols. Often, the most convenient way of getting them is to use the syntax quote as in the example above.
You can drop the wrapping collection if you’re only checking a single function:
(defspec-test test-foo-spec `yet-another-function)
You might find the enumerate-namespace
function useful
for checking all the functions of one or more namespaces against their
respective specs.
(defspec-test test-namespaces (stest/enumerate-namespace 'my.namespace))
(defspec-test test-namespaces (stest/enumerate-namespace '[my.other-namespace
yet-another.namespace]))
(assuming stest
is an alias for spec.test
).
If your test suite is getting too slow because of spec checks, you might want to
restrict the number of values tested. For instance, this code would test
my-function
for 10 different inputs.
(defspec-test test-foo-spec `my-function {:opts {:num-tests 10}})
The underlying mechanism is a little convoluted. If you pass a map as third
parameter to defspec-test
, that parameter will get passed on as the opts to
stest/check
.
stest/check
will in turn pass a special parameter on to
quick-check
. However, for some crazy reason, that parameter is
named differently in Clojure (:clojure.spec.test.check/opts
) and ClojureScript
(:clojure.test.check/opts
).
To remedy this, Mimolette will translate the namespace-less :opts
key to
whichever key the underlying specs implementation understands.
Finally, the :num-tests
key adds another round of magic: it isn’t actually
interpreted by quick-check
. Instead, stest/check
passes it as the num-tests
parameter to quick-check
.
###No tests are generated
defspec-test
will only generate tests for specs that it knows about, so you
want to make sur that your specs are actually loaded. If your specs reside in
the same namespace as your functions, then that’s already taken care of. If your
specs have a namespace of their own, then make sure to require that from your
tests. This is especially true in ClojureScript, Clojure seems to be more
forgiving here.
- There is no test suite. Now that side-effect-free functions have been broken out of the original macro, they should be easier to test.
- The handling of options is incredibly convoluted and ought to be straightened out.
- You sometimes get the stack trace shown below. This probably happens when spec gives up generating input values after too many failed attempts, and should be handled more gracefully.
Uncaught exception, not in assertion.
expected: nil
actual: java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.AssertionError
The notable changes to this project are documented in the change log.
I (Frederic Merizen) am not the original author of this library.
The macro that evolved to become Mimolette made its first public appearance on
November 4th 2016, when Kenny Williams published his
‘solution to integrating clojure.spec.test/check
with
clojure.test
’ on the #clojure-spec channel of the
clojurians slack.
He didn’t release the macro as a lib at the time, partly because it wasn’t clear if the practice it enabled was actually recommended, and partly because he felt that the core team might be working on something similar.
On November 19th 2016, Timothy Washington
asked on Stack Overflow how to run spec checks from
clojure.test
. On November 21st he answered his own question with the
defspec-test
macro from the clojurians slack.
This is were I found the macro. I wanted to use it for my own projects. I’m no great fan of reuse by cut and paste, and so I decided to give it a home on Clojars, added ClojureScript support, and broke the macro down into simpler components, and thus Mimolette was born.
I would like to thank Kenny and Timothy for their feedback and helping me piece together this history.
Distributed under the MIT license. Copyright © 2017 Frederic Merizen & Kenny Williams.