我在Clojure应用程序中提供了三项服务:
Service A
:与第三方API交互,从而在外部服务中引起潜在的危险且不可逆的更改(可能不是我写的)Service B
:使用服务A来实现其目标Service C
:使用服务B来实现自己的目标我需要为Service C编写集成测试,而不要调用第三方,因为它们既不提供一组测试端点,也不提供撤消更改的方法。
我看到的两个选项是:
将被调用的函数传递到服务C中,就像如何以OOP语言注入服务实例一样。实际使用Service C时,这会导致很多额外的开销。
使用with-redefs-fn
模拟服务A中的危险功能。这需要了解我可能无法控制的服务的实现细节。
我对使用功能语言进行测试有些陌生,因此很可能我缺少明显的东西。
答案 0 :(得分:1)
如果您了解有关服务实现的一些详细信息,并且这些信息大多数都是用Java编写的,则可以使用proxy
创建您所选择的类或接口的替代实现。想在测试期间进行约束。
示例如下:
(let [proxy-a (proxy [com.dangerous.ServiceA] []
(launchMissiles [x y z]
(log/info "Phew! we didn't fire a missile during tests!")))
proxy-b (proxy [com.example.ServiceB] []
(callServiceA [x y z]
(.launchMissiles proxy-a x y z)))
proxy-c (proxy [com.example.ServiceC] [x]
(callServiceB [x]
(.callServiceB proxy-b x 1 2)))]
;; Perform a test on the outer proxy with:
(.callServiceB proxy-c "testing!")
答案 1 :(得分:1)
如果我正确理解了您的用例,则可以通过使用clj-fake-http模拟整个Service A来避免在对Service C的集成测试中调用ServiceA。我在我的一个工作项目中非常愉快地使用了该库,并且可以强烈推荐它。
这假设服务A实际上是您正在与之交谈的另一个过程。如果服务A与服务C处于同一流程中,则您最好不要像服务A那样去掉对第三方API的调用。
答案 2 :(得分:0)
使用选项#2,但使用with-redefs
(几乎不需要with-redefs-fn
。请参阅
示例:
(ns http)
(defn post [url] ; dummy fn for testin
{:body "Hello world"})
(ns app
(:require [clojure.test :refer [deftest is run-tests]]))
(deftest is-a-macro
(with-redefs [http/post (fn [url] {:body "Goodbye world"})]
(is (= {:body "Goodbye world"} (http/post "http://service.com/greet")))))
(run-tests) ;; test is passing