clojure.test
for ExpectationsA clojure.test
-compatible version of the classic Expectations testing library.
This library brings expect
, more
, more-of
, etc from Expectations into the
clojure.test
world to be used instead of (or in addition to) the familiar is
macro. This library has no dependencies, other than clojure.test
itself, and
should be compatible with all existing clojure.test
-based tooling in editors
and command-line tools.
You can either use deftest
from clojure.test
, or defexpect
from
this library to wrap your tests.
(ns my.cool.project-test
(:require [clojure.test :refer [deftest is]]
[expectations.clojure.test :refer :all]))
;; mix'n'match libraries:
(deftest mixed
(is 2 (+ 1 1))
(expect even? (+ 1 1)))
;; simple equality tests:
(defexpect equality
(expect 1 (* 1 1))
(expect "foo" (str "f" "oo")))
;; the expected outcome can be a regular expression:
(defexpect regex-1
(expect #"foo" "It's foobar!"))
;; since that has only a single expectation, it can be written more succinctly:
(defexpect regex-2 #"foo" "It's foobar!")
;; the expected outcome can be an exception type:
(defexpect divide-by-zero ArithmeticException (/ 12 0))
;; the expected outcome can be a predicate:
(defexpect no-elements empty? (list))
;; the expected outcome can be a type:
(defexpect named String (name :foo))
;; if the actual value is a collection, the expected outcome can be an element or subset "in" that collection:
(defexpect collections
(expect {:foo 1} (in {:foo 1 :cat 4}))
(expect :foo (in #{:foo :bar}))
(expect :foo (in [:bar :foo])))
Just like deftest
, the defexpect
macro creates a function that contains the test(s). You can run each function individually:
user=> (equality)
nil
If the test passes, nothing is printed, and nil
is returned. Let's look at a failing test:
user=> (defexpect inequality (* 2 21) (+ 13 13 13))
#'user/inequality
user=> (inequality)
FAIL in (inequality) (.../README.md:67)
expected: (=? (* 2 21) (+ 13 13 13))
actual: 39
nil
The output is produced by clojure.test
's standard reporting functionality.
The =?
operator is an extension to clojure.test
's assert-expr
multimethod
that allows for Expectations style of predicate-or-equality testing (based on
whether the "expected" expression resolves to a function or some other value):
user=> (defexpect indivisible odd? (+ 1 1))
#'user/indivisible
user=> (indivisible)
FAIL in (indivisible) (.../README.md:83)
expected: (=? odd? (+ 1 1))
actual: (not (odd? 2))
nil
Here we see the predicate (odd?
) being applied in the "actual" result from
clojure.test
.
expectations.clojure.test
supports the following features from Expectations so far:
named
abovedivide-by-zero
aboveregex-1
and regex-2
above(expect expected-expr (from-each [a values] (actual-expr a)))
(expect expected-expr (in actual-expr))
-- see collections
above(expect (more-of destructuring e1 a1 e2 a2 ...) actual-expr)
(expect (more-> e1 a1 e2 a2 ...) actual-expr)
-- where actual-expr
is threaded into each a1
, a2
, ... expression(expect (more e1 e2 ...) actual-expr)
(expect expected-expr (side-effects [fn1 fn2 ...] actual-expr))
Read the Expectations documentation for more details of these features.
Tests defined with defexpect
behave just like tests defined with deftest
and
all of the existing clojure.test
-based tooling will work with them, including
fixtures, test runners, and other libraries that patch clojure.test
to improve
its error reporting and other features.
Given the streamlined simplicity of Expectations, you might wonder why you
would want to migrate your Expectations test suite to clojure.test
-style
named tests? The short answer is tooling! Whilst Expectations has
well-maintained, stable plugins for Leiningen and Boot, as well as an Emacs mode,
the reality is that Clojure tooling is constantly evolving and most of those
tools -- such as the excellent https://cider.readthedocs.io/en/latest/,
https://cursive-ide.com/,
and the more recent https://atom.io/packages/proto-repl
and Chlorine (both for Atom) --
are going to focus on Clojure's built-in testing library first.
Support for the original form of Expectations, using unnamed tests, is
non-existent in Cursive, and can be problematic in other editors.
A whole ecosystem
of tooling has grown up around clojure.test
and to take advantage of
that with Expectations, we either need to develop compatible extensions to each
and every tool or we need Expectations to be compatible with clojure.test
.
One of the big obstacles for that compatibility is that, by default, Expectations
generates "random" function names for test code (the function names are based on the
hashcode of the text form of the expect
body), which means the test
name changes whenever the text of the test changes. To address that, the new
expectations.clojure.test
namespace introduces named expectations via
the defexpect
macro (mimicking clojure.test
's deftest
macro). Whilst this goes against the [https://clojure-expectations.github.io/odds-ends.html](Test Names
philosophy) that Expectations was created with, it buys us a lot in terms of
tooling support!
Aside from the obvious difference of providing names for tests -- essential for
compatibility with clojure.test
-based tooling -- here are the other differences
to be aware of:
clojure.test
-based tooling -- lein test
, boot test
, and Cognitect's test-runner
-- instead of the Expectations-specific tooling.in-context
, before-run
, after-run
machinery of Expectations, you can just use clojure.test
's fixtures machinery (use-fixtures
).freeze-time
and redef-state
are not (yet) implemented.CustomPred
protocol is not implemented -- you can use plain is
and extend clojure.test
's assert-expr
multimethod if you need that level of control.To test, run clj -A:test:runner
.
Add tests(!) and more examples.
Copyright © 2018-2019 Sean Corfield, all rights reserved.
Distributed under the Eclipse Public License version 1.0.
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close