1

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

这类似于:Mocking Clojure 协议中的问题,但使用模拟。

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

编辑 - 这是一个例子:

有一个协议及其实现:

(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))))
4

2 回答 2

1

为后人。这是一个工作测试:

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

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

奇怪的观察。对于使用其他语法在协议上调用函数的函数,相同的测试方式不起作用。不知道为什么。

(defn test-me2 [n]
  (let [t (gimme)]
     (.go-bump t n)))
于 2013-10-28T16:01:57.900 回答
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

在 GitHub 上也有一个关于他的讨论,其中有几个用于运行时调度模拟的替代方案。

于 2013-10-28T14:04:25.437 回答