Midje中的模拟协议实现

时间:2013-10-28 11:30:11

标签: unit-testing clojure mocking midje

有没有办法用Midje(clojure)使用类似“提供”的语法来模拟(而不是存根)协议功能?

这与Mocking Clojure protocols中的问题类似,但有嘲弄。

更详细:我有一个协议和一个返回实现它的东西的函数。我想将函数存根以返回协议的模拟,并且我想对模拟协议“实现”的一个函数注册期望。

编辑 - 这是一个例子:

有一个协议及其实施:

(defprotocol Thiny (go-bump [_ _]))
(deftype TheThing []
  Thiny
  (go-bump [_ _] 23))

有一个函数可以返回协议的实现:

(defn gimme [] (TheThing.))

TheThing 可能是数据库或网络连接,也可能是您想要在测试中摆脱的其他令人讨厌的事情。

然后,我想要测试的功能:

(defn test-me [n]
  (let [t (gimme)]
    (-> t (go-bump n))))

我想确保用 n 调用 go-bump

这是我第一次尝试创建测试。但它只完成了一半,我想设置对 gimme 返回的 Thiny 的期望:

(fact
  (test-me 42) => 42
  (provided (gimme) => (reify Thiny (go-bump [_ n] n))))

2 个答案:

答案 0 :(得分:1)

模拟协议应该与模拟函数没有区别,你需要考虑第一个分析参数是this,因此模拟函数应该考虑这种类型。

例如,给定协议P

(defprotocol P 
  (foo [this]) 
  (bar-me [this] [this y]))

类型Integer

的扩展
(extend-protocol P
  Integer
  (foo [this]
    (+ this 4))
  (bar-me [this]
    (* this 5))
  (bar-me [this y]
    (+ this y)))

您可以先检查几件事,Long没有实施:

(foo 3)
=>  IllegalArgumentException No implementation of method: :foo of 
    protocol: #'P found for class: java.lang.Long  
    clojure.core/-cache-protocol-fn (core_deftype.clj:541)

按预期为ints

工作
(foo (int 3))
=> 7

现在定义事实并根据需要提供协议功能:

(fact
  (foo (int 3)) => 7
  (provided (foo 3) => 8))

在这种情况下,它正确失败,因为模拟为指定的输入返回8而不是7

FAIL at (test.clj:20)
     Expected: 7
     Actual: 8

如果值模拟不够,而您需要提供替代实现,请查看with-redefs-fn,您可以用它包装测试函数。

 => (defn f [] false)
 => (println (f))
 ;; false
 => (with-redefs-fn {#'f (fn [] true)}
 #(println (f)))
 ;; true

还有a discussion in GitHub about his有几个运行时调度模拟的替代方案。

答案 1 :(得分:1)

为后人。这是一个有效的测试:

(fact
  (test-me 42) => 42
  (provided (gimme) => :the-thingy)
  (provided (go-bump :the-thingy 42) => 42))

诀窍是使用多个相互关联的提供语句。

Wierd观察。相同的测试方法不适用于使用其他语法调用协议上的函数的函数。不知道为什么。

(defn test-me2 [n]
  (let [t (gimme)]
     (.go-bump t n)))
相关问题