Particularly useful for when namespace level fixtures with use-fixtures
is not specific enough.
;; Add the following to dependencies in your project.clj
[fixturex "0.3.2"]
fixturex
is meant to make using and defining fixtures in tests just a tiny bit easier.
It is a very small and simple library of tiny macros.
Why am I not introducing the core namespace first?
fixturex.higher
makes it a bit more concise to define fixtures which is necessary to show off the core part of this library.
(use 'fixturex.higher)
(before (setup)) ; → (fn [f#] (setup) (f#))
(after (tear-down)) ; → (fn [f#] (f#) (tear-down))
(before-and-after (setup) (tear-down)) ; → (fn [f#] (setup) (f#) (tear-down))
(declare ^:dynamic *x*)
(around binding [*x* 1]) ; → (fn [f#] (binding [*x* 1] (f#)))
(wrap binding *x* 1) ; → (fn [f#] (binding [*x* 1] (f#)))
(redefs x 1) ; → (fn [f#] (with-redefs [x 1] (f#)))
(with x 1) ; → (fn [f#]
; (declare x)
; (with-redefs [x (delay 1)] (f#)))
The with-fixtures
macro can be use to execute some body of code with a sequence of fixtures.
(require '[clojure.test :refer [is]])
(with-fixtures [(before (setup))
(with conn (connect-to-db))
(with x 1)]
(do-something conn x)
(with-fixtures [(with x 2)]
(is (= @x 2)))
(is (= @x 1)))
There is also a function version, with-fixtures-fn
.
fixtures defines deftest-fx
and testing-fn
.
(defn connect-to-db [] ...)
(defn dissconnect-from-db [] ...)
(deftest-fx test-user-creation [(before-and-after (connect-to-db)
(dissconnect-from-db))]
...)
They use with-fixtures
internally and are just a bit of sugar.
This namespace supports dynamic binding like in RSpec.
It accomplishes this by providing some functions which merge bindings onto a dynamic var (*context*
) and by rewriting forms.
Some totally ridiculous examples follow.
(require [fixturex.context :refer :all])
This macro merges the given bindings onto the context and rewrites the body so symbols that match keys in the context are lookups.
(with-context [:foo 1
:bar (inc foo)]
(assert (= bar 2)))
In RSpec this looks like:
context do
let(:foo) { 1 }
let(:bar) { 2 }
it { expect(bar).to eq(2) }
end
This is just a shortcut for combining clojure.test/testing
and with-context
.
(testing-ctx "description of context" [...bindings...]
...)
(testing "description of context"
(with-context [...bindings...]
...))
This is just a shortcut for combining clojure.test/deftest
and with-context
.
(deftest-ctx test-something [...bindings...]
...)
(deftest test-something
(with-context [...bindings...]
...))
Creates a fixture that adds bindings to the context.
(require '[fixturex.core :refer [with-fixtures]])
(def a-fixture (where :foo 2))
(with-context [:foo 1]
(assert (= foo 1))
(with-fixtures [a-fixture]
(assert (= foo 2))))
Functions which lookup in the context can be defined outside of where the context is defined. There are several methods to lookup.
(defn bar-is-one [] (scoped [bar] (assert (= bar 1))))
(defn foo-is-two [] (assert (= ($ foo) 2)))
(defn lol-is-three [] (assert (= (lookup :lol) 3)))
(with-context [:bar 1
:foo 2
:lol 3]
(bar-is-one)
(foo-is-two)
(lol-is-three))
fixturex uses the same mechanism for combining fixtures that clojure.test
does.
This means that you must be careful.
It is easy to write a bad fixture and next to impossible to tell if a fixture does not do what the author intended.
Take the following example:
(require '[clojure.test :refer [is]])
(require '[fixturex.core :refer [with-fixtures]])
(with-fixtures []
(is (= 1 2))) ; → false
This prints:
FAIL in ...
expected: (= 1 2)
actual: (not (= 1 2))
However, if we pass in a fixture which does not invoke its argument:
(with-fixtures [(fn bad-fx [f] :derp)]
(is (= 1 2))) ; → :derp
Nothing is printed.
If you have something like this in tests it may appear that certain tests are passing when in fact they are not being invoked.
Copyright © 2014 Ryan V McGowan
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.