Clojure单元测试:检查函数是否被调用

Att*_*lah 11 tdd unit-testing clojure mocking midje

我正在尝试为我的clojure函数编写一些单元测试(我正在使用clojure.test,但如果需要我可以切换到midje).

我有一个函数,如下所示:

(defn GenerateNodes
   [is-sky-blue? hot-outside? name]
   (cond
     (is-sky-blue? name) (generate-sky-nodes)
     (hot-outside?) (generate-hot-nodes)))
Run Code Online (Sandbox Code Playgroud)

单元测试此函数时,我想编写以下测试用例:

(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?))
Run Code Online (Sandbox Code Playgroud)

如何断言函数generate-sky-nodes被调用?或不 ?我会在C#或java中使用一个模拟框架,但我不知道clojure.

noi*_*ith 10

您已经拥有的功能版本不远.我改变了一些东西,以更加惯用于Clojure.

以下假设generate-sky-nodes和generate-hot-nodes都返回一些值(这可以在它们具有的任何副作用之外完成),即:

(defn generate-sky-nodes
   []
   (doseq [i (range 10)] (do-make-sky-node i))
   :sky-nodes)
Run Code Online (Sandbox Code Playgroud)

然后,您的生成节点调整如下:

(defn generate-nodes
  [sky-blue? hot-outside? name]
  (cond
   (sky-blue? name) (generate-sky-nodes)
   (hot-outside?) (generate-hot-nodes)))
Run Code Online (Sandbox Code Playgroud)

最后,测试的功能版本:

(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)))))
Run Code Online (Sandbox Code Playgroud)

一般的想法是你不测试它做了什么,你测试它返回什么.然后你安排你的代码,以便(只要有可能)所有与函数调用有关的内容都是它返回的内容.

另外一个建议是通过使用generate-sky-nodesgenerate-hot-nodes返回副作用来减少发生副作用的地方数量:

(defn generate-sky-nodes
   []
   (fn []
    (doseq [i (range 10)] (do-make-sky-node i))
    :sky-nodes))
Run Code Online (Sandbox Code Playgroud)

你的电话generate-nodes将如下所示:

(apply (generate-nodes blue-test hot-test name) [])
Run Code Online (Sandbox Code Playgroud)

或者更简洁(虽然如果你对Clojure不太熟悉,你会感到奇怪):

((generate-nodes blue-test hot-test name))
Run Code Online (Sandbox Code Playgroud)

(在上述测试代码中作必要的修改后,测试也适用于此版本)


Chi*_*ron 9

您可以自己编写一个宏来模拟函数并检查函数是否被调用.或者您可以使用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")))
Run Code Online (Sandbox Code Playgroud)

  • 只是一个警告:此库自2012年以来未更新,似乎与Clojure 1.9不兼容. (3认同)