I'm trying to write some unit tests for my clojure function (I'm using clojure.test, but I can switch to midje if necessary).
I have a function that reads like :
(defn GenerateNodes
[is-sky-blue? hot-outside? name]
(cond
(is-sky-blue? name) (generate-sky-nodes)
(hot-outside?) (generate-hot-nodes)))
when unit testing this function, I want to write the following test case :
(deftest when-sky-blue-then-generate-sky-nodes
(let [is-sky-blue true]
(GenerateNodes (fn[x] println "sky nodes generated."))
(is (= true Was-generate-hot-nodes-called?))
How can I assert that the function generate-sky-nodes was called ? or not ? I would use a mocking framework in C# or java, but I don't know about clojure.
What you have already is not far from a working functional version. I changed things around a bit to be more idiomatic to Clojure.
The following assumes that generate-sky-nodes and generate-hot-nodes each return some value (this can be done in addition to any side effects they have), i.e.:
(defn generate-sky-nodes
[]
(doseq [i (range 10)] (do-make-sky-node i))
:sky-nodes)
then, your generate-nodes is adjusted as follows:
(defn generate-nodes
[sky-blue? hot-outside? name]
(cond
(sky-blue? name) (generate-sky-nodes)
(hot-outside?) (generate-hot-nodes)))
and finally, the functional version of the tests:
(deftest when-sky-blue-then-generate-sky-nodes
(let [truthy (constantly true)
falsey (constantly false)
name nil]
(is (= (generate-nodes truthy falsey name)
:sky-nodes))
(is (= (generate-nodes truthy truthy name)
:sky-nodes))
(is (not (= (generate-nodes falsey falsey name)
:sky-nodes)))
(is (not (= (generate-nodes falsey truthy name)
:sky-nodes)))))
The general idea is that you don't test what it did, you test what it returns. Then you arrange your code such that (whenever possible) all that matters about a function call is what it returns.
An additional suggestion is to minimize the number of places where side effects happen by using generate-sky-nodes
and generate-hot-nodes
to return the side effect to be carried out:
(defn generate-sky-nodes
[]
(fn []
(doseq [i (range 10)] (do-make-sky-node i))
:sky-nodes))
and your call of generate-nodes
would look like the following:
(apply (generate-nodes blue-test hot-test name) [])
or more succinctly (though admittedly odd if you are less familiar with Clojure):
((generate-nodes blue-test hot-test name))
(mutatis mutandis in the above test code the tests will work with this version as well)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With