Clojure中如何在协议实现中对另一协议调用进行插桩?
解决Conjure插桩协议方法的问题
嘿,我明白你作为Clojure新手面对这个问题的困惑——协议方法的插桩和普通defn函数确实有点不一样。让我一步步给你讲清楚怎么处理:
首先,你要明白:Clojure的协议方法本质上是多态函数,它们会被绑定到一个命名空间级别的var上。所以当你在FooImpl里调用(.bar2 protocol-2)时,其实和调用(bar2 protocol-2)是等价的,都是在调用协议Protocol2定义的bar2方法对应的那个函数var。
具体怎么做?
假设你的Protocol2定义在my.project.protocols这个命名空间下,那么在instrumenting里,你需要引用这个方法的var,格式是#'my.project.protocols/bar2(注意前面的#'是必须的,因为Conjure需要的是var对象,而不是符号)。
给你一个完整的示例,方便你对照:
1. 协议和实现代码
(ns my.project.protocols) ;; 定义Protocol2 (defprotocol Protocol2 (bar2 [this arg])) ;; 定义你要实现的主协议 (defprotocol MyProtocol (bar [this])) ;; 实现MyProtocol的deftype (deftype FooImpl [^Protocol2 protocol-2] MyProtocol (bar [_] ;; 满足条件后调用bar2 (when true ;; 这里替换成你的实际条件 (.bar2 protocol-2 "test-param"))))
2. 测试代码(使用Conjure插桩)
(ns my.project.test (:require [conjure.core :as conjure] [my.project.protocols :as p])) (deftest foo-bar-calls-bar2-test ;; 创建一个Protocol2的mock实例 (let [mock-proto2 (reify p/Protocol2 (bar2 [_ arg] nil))] ;; 对bar2方法进行插桩 (conjure/instrumenting [#'p/bar2] ;; 执行被测试的代码 (p/bar (->FooImpl mock-proto2)) ;; 验证调用次数和参数 (conjure/verify-called-once-with-args #'p/bar2 mock-proto2 "test-param"))))
关键注意点
- 一定要用
#'来引用协议方法的var,不能只写符号p/bar2,否则Conjure无法找到要插桩的目标。 - 不管你是用Java互操作风格的
.bar2还是函数风格的bar2调用,插桩的目标都是同一个协议方法var,两种调用方式都会被捕获到。 - 确保你的mock实例正确实现了
Protocol2,否则调用时会触发ClassCastException,影响测试。
内容的提问来源于stack exchange,提问作者errob37
相关产品推荐
相关产品推荐

