有没有办法用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))))
答案 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)))