An alternative to clojure.test
, aiming to be feature-rich and easily
extensible.
Isn't
clojure.test
good enough?
Lazytest is designed to be a standalone test system for Clojure,
disconnected from the built-in clojure.test
. clojure.test
has
existed since 1.1 and while it's both ubiquitous and useful, it has
a number of
problems.
Other alternatives such as Midje
and expectations
have attempted
to correct some of those issues and they made good progress, but many
(such as Midje
) relied on non-list style (test => expected
) and
most don't worked well with modern repl-driven development practices
(using gynsym
s instead of named test vars).
I like the ideas put forth in Alessandra's post above about Lazytest and hope to experiment with achieving them 10 years later, while borrowing heavily from the work in both the Clojure community and test runners frameworks in other languages.
Add it to your deps.edn or project.clj:
{:aliases
{:test {:extra-deps {io.github.noahtheduke/lazytest {:mvn/version "0.2.0"}}
:extra-paths ["test"]
:main-opts ["-m" "lazytest.main"]}}}
In a test file:
(ns example.readme-test
(:require [lazytest.core :refer [defdescribe decribe expect it]]))
(defdescribe seq-fns-test
(describe keep
(it "should reject nils"
(expect (= '(1 false 2 3) (keep identity [nil 1 false 2 3]))))))
From the command line:
$ clojure -M:test
example.readme-test
seq-fns-test
#'clojure.core/keep
√ should reject nils
Ran 1 test cases in 0.00243 seconds.
0 failures.
The primary api is found in lazytest.core
namespace. It mimics the
behavior-driven testing style popularized by libraries such as
RSpec and Mocha.
Use the defdescribe
macro to create a group of tests. Start the
group with a name and an optional documentation string.
(ns examples.readme.groups
(:require [lazytest.core :refer [defdescribe describe expect it]]))
(defdescribe seq-fns-test "a test of clojure core fns" ...)
Within a defdescribe
group, use it
to create a test example. Start
your example with a documentation string describing what should
happen, followed by an expression that throws if it it fails, such as
Clojure's built-in assert
or Lazytest's provided expect
.
(defdescribe +-test "with integers"
(it "computes the sum of 1 and 2"
(expect (= 3 (+ 1 2))))
(it "computes the sum of 3 and 4"
(assert (= 7 (+ 3 4)))))
The expect
macro is like assert
but carries more information about
the failure. It throws an exception if the expression does not
evaluate to logical true.
If the code inside the it
macro runs to completion without throwing
an exception, the test example is considered to have passed.
Test groups may be nested inside other groups with describe
, which
has the same syntax as defdescribe
but does not define a top-level
Var (thus the similar names).
(ns examples.readme.nested
(:require [lazytest.core :refer [defdescribe describe expect it]]))
(defdescribe addition-test "Addition"
(describe "of integers"
(it "computes small sums"
(expect (= 3 (+ 1 2))))
(it "computes large sums"
(expect (= 7000 (+ 3000 4000)))))
(describe "of floats"
(it "computes small sums"
(expect (> 0.00001 (abs (- 0.3 (+ 0.1 0.2))))))
(it "computes large sums"
(expect (> 0.00001 (abs (- 3000.0 (+ 1000.0 2000.0))))))))
The defdescribe
, describe
, expect-it
, and it
macros all take
an optional metadata map immediately after the docstring.
Adding :focus true
to this map will cause only that test/suite to
be run. Removing it will return to the normal behavior (run all
tests).
(defdescribe my-test
"fancy test"
{:focus true}
...)
The smallest unit of testing is a test case, which is a function
(see lazytest.test-case/test-case
). When the function is called, it
may throw an exception to indicate failure. If it does not throw an
exception, it is assumed to have passed. The return value of a test
case is always ignored. Running a test case may have side effects.
NOTE: The macros lazytest.describe/it
and
lazytest.describe/expect-it
create test cases.
Tests cases are organized into suites. A test suite is a function
(see lazytest.suite/suite
) that returns a test sequence. A test
sequence (see lazytest.suite/test-seq
) is a sequence, possibly lazy,
of test cases and/or test suites. Suites, therefore, may be nested
inside other suites, but nothing may be nested inside a test case.
NOTE: The macros lazytest.describe/defdescribe
and
lazytest.describe/describe
create test suites.
A test suite function may NOT have side effects; it is only used to generate test cases and/or other test suites.
A test runnner is responsible for expanding suites (see
lazytest.suite/expand-suite
) and running test cases (see
lazytest.test-case/try-test-case
). It may also provide feedback on
the success of tests as they run.
The test runner also returns a sequence of results, which are either
suite results (see lazytest.suite/suite-result
) or test case
results (see lazytest.test-case/test-case-result
). That sequence of
results is passed to a reporter, which formats results for display
to the user. Multiple reporters are provided, see the namespace
lazytest.reporters
.
Put the following in .emacs
:
(eval-after-load 'clojure-mode
'(define-clojure-indent
(defdescribe 'defun)
(describe 'defun)
(given 'defun)
(expect-it 'defun)
(it 'defun)))
Originally by Alessandra Sierra.
Currently developed by Noah Bogart.
Licensed under Eclipse Public License 1.0
Can you improve this documentation? These fine people already did:
Stuart Sierra & Noah BogartEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close