[英]Clojure Unit testing : Check if a function was called
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). 我正在尝试为我的clojure函数编写一些单元测试(我正在使用clojure.test,但如果需要我可以切换到midje)。
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 ? 如何断言函数generate-sky-nodes被调用? or not ?
或不 ? I would use a mocking framework in C# or java, but I don't know about clojure.
我会在C#或java中使用一个模拟框架,但我不知道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.
我改变了一些东西,以更加惯用于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), ie: 以下假设generate-sky-nodes和generate-hot-nodes都返回一些值(这可以在它们具有的任何副作用之外完成),即:
(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: 另外一个建议是通过使用
generate-sky-nodes
和generate-hot-nodes
来返回要执行的副作用来最小化副作用发生的位置数:
(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: 你对
generate-nodes
调用如下所示:
(apply (generate-nodes blue-test hot-test name) [])
or more succinctly (though admittedly odd if you are less familiar with Clojure): 或者更简洁(虽然如果你对Clojure不太熟悉,你会感到奇怪):
((generate-nodes blue-test hot-test name))
(mutatis mutandis in the above test code the tests will work with this version as well) (在上述测试代码中作必要的修改后,测试也适用于此版本)
You can write a Macro yourself to mock functions and check whether a function got called or not. 您可以自己编写一个宏来模拟函数并检查函数是否被调用。 Or you can use expect-call library.
或者您可以使用expect-call库。
(defn check-error [a b]
(when (= a :bad-val)
(log :error b)))
; This will pass
(deftest check-logging
(with-expect-call (log [:error _])
(check-error :bad-val "abc")))
; This will fail
(deftest check-logging-2
(expect-call (log [:error _])
(check-error :good-val "abc")))
Using Midje 's checkables : 使用Midje的支票 :
(unfinished is-sky-blue? hot-outside?)
(facts "about GenerateNodes"
(fact "when the sky is blue then sky nodes are generated"
(GenerateNodes is-sky-blue? hot-outside? ..name..) => ..sky-nodes..
(provided
(is-sky-blue? ..name..) => true
(generate-sky-nodes) => ..sky-nodes..
(generate-hot-nodes) => irrelevant :times 0)))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.