Clojure testing with Midje

Testing with Midje
Tobias Bayer
:clojureD 2015, Berlin
BBC, http://ichef.bbci.co.uk/naturelibrary/images/ic/credit/640x395/h/hi/highland_midge/highland_midge_1.jpg
Midge
Midje
Tobias Bayer
inovex GmbH
[email protected]
codebrickie
Why Midje?
Non-lispy expectation syntax
(conj [1 2] 3) => [1 2 3]
vs
(is (= [1 2 3] (conj [1 2] 3)))
Why Midje?
Helpers and tools
Checking functions for expectations
Simple stubbing and mocking
Auto-testing
...
Basic Building Blocks
Facts
Checkables
Checkers
Prerequisites
Facts
Midje equivalent of a test
Facts
(facts "about +"
(fact "1 plus 2 equals 3"
(+ 1 2) => 3)
(fact
(+ -1 -1) => -2))
Facts
(future-fact "it returns fancy"
(fancy-function) => "fancy")
;; => WORK TO DO
Checkables
(facts "about +"
(fact "1 plus 2 equals 3"
(+ 1 2) => 3))
Checkables
(facts "about +"
(fact "1 plus 2 equals 3"
(+ 1 2) => 3))
Checkables
(facts "about +"
(fact
(+ 1 1) =not=> 3))
Checkers
Can be used instead of values on the right side
of a checkable
Checkers - contains
(facts "about my list"
(fact "it contains the value 5"
'(1 2 3 4 5 6) => (contains 5))
(fact "it contains the values 2 and 3"
'(1 2 3 4 5 6) => (contains 2 3))
(fact "it contains an odd number followed by
an even number"
'(1 2 3 4 5 6) => (contains odd? even?)))
Checkers - contains
(facts "about my map"
(fact "the value of x is 1"
{:x 1 :y 2} => (contains {:x 1}))
(fact "the value of y is even"
{:x 1 :y 2} => (contains {:y even?})))
Checkers - throws
(throwing-function) =>
(throws Exception)
(throwing-function) =>
(throws Exception "foo")
(throwing-function) =>
(throws Exception #"(foo|bar)")
Checkers - anything/irrelevant
(fact "insert-value has a side effect"
(reset-values) => irrelevant
(exists-value? "foo") => falsey
(insert-value "foo") => irrelevant
(exists-value? "foo") => truthy)
Checkers - own checkers
(defn each-element-is-one-of [expected-elements]
(fn [actual]
(every? (set expected-elements) actual)))
(fact "each element is one of 1-10"
'(1 2 3 4 5 6) => (each-element-is-one-of (range 1 11)))
Prerequisites
OO-world: stubbing and mocking
Prerequisites - Stub
(defn find-user [username]
;; Code that finds the user in the database
)
(defn authenticate [username password]
(let [user (find-user username)]
(if (= (:password user) password)
user)))
(fact "it authenticates a user with a valid password"
(authenticate "the fly" "12345") => truthy
(provided
(find-user "the fly") =>
{:name "the fly" :password "12345"}))
Prerequisites - Mock
(fact "it calls the second function 5 times with argument
'foo'"
(first-function "foo") => irrelevant
(provided
(second-function "foo") => irrelevant :times 5))
(fact "it never calls the third function with any
argument"
(first-function "foo") => irrelevant
(provided
(third-function anything) => irrelevant :times 0))
Project setup
~/.lein/profiles.clj
{:user {:plugins [[lein-midje "3.1.3"]]}}
Project setup
lein new midje midje-intro
Project setup
lein new midje midje-intro
Project setup
lein new midje midje-intro
DEMO