如何伪造涉及潜在危险动作的第三方API的嵌套使用?

时间:2019-05-09 20:33:18

标签: clojure automated-tests

我在Clojure应用程序中提供了三项服务:

  • Service A:与第三方API交互,从而在外部服务中引起潜在的危险且不可逆的更改(可能不是我写的)
  • Service B:使用服务A来实现其目标
  • Service C:使用服务B来实现自己的目标

我需要为Service C编写集成测试,而不要调用第三方,因为它们既不提供一组测试端点,也不提供撤消更改的方法。

我看到的两个选项是:

  • 将被调用的函数传递到服务C中,就像如何以OOP语言注入服务实例一样。实际使用Service C时,这会导致很多额外的开销。

  • 使用with-redefs-fn模拟服务A中的危险功能。这需要了解我可能无法控制的服务的实现细节。

我对使用功能语言进行测试有些陌生,因此很可能我缺少明显的东西。

3 个答案:

答案 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!")

此处有更多详细信息:https://clojuredocs.org/clojure.core/proxy

答案 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