在 Clojure 测试中存根 HTTP 请求的策略
Strategy for stubbing HTTP requests in Clojure tests
我想知道在 Clojure 集成测试中是否有一种广泛使用的模式或解决方案用于将出站 HTTP 请求存根到第三方(la Ruby 的 webmock)。我希望能够在高级别(例如,在设置函数中)存根请求,而不必将我的每个测试包装在 (with-fake-http [] ...)
之类的东西中或不得不求助于依赖注入。
这是动态变量的好用例吗?我想我可以在设置步骤中进入有问题的命名空间,并将副作用函数设置为无害的匿名函数。然而,这感觉很笨拙,我不喜欢更改应用程序代码以适应我的测试的想法。 (它也不比上面提到的解决方案好多少。)
交换包含假函数的特定于测试的 ns 是否有意义?在我的测试中有没有一种干净的方法可以做到这一点?
你可以看到一个使用ring/compojure框架的好例子:
> lein new compojure sample
> cat sample/test/sample/handler_test.clj
(ns sample.handler-test
(:require [clojure.test :refer :all]
[ring.mock.request :as mock]
[sample.handler :refer :all]))
(deftest test-app
(testing "main route"
(let [response (app (mock/request :get "/"))]
(is (= (:status response) 200))
(is (= (:body response) "Hello World"))))
(testing "not-found route"
(let [response (app (mock/request :get "/invalid"))]
(is (= (:status response) 404)))))
更新
对于出站 http 调用,您可能会发现 with-redefs
有用:
(ns http)
(defn post [url]
{: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
本例中,原函数post
returns"Hello world"。在单元测试中,我们使用返回 "Goodbye world".
的存根函数临时覆盖 post
完整文档 is at ClojureDocs.
前阵子我也遇到过类似的情况,我找不到任何满足我需求的 Clojure 库,所以我创建了自己的库 Stub HTTP。使用示例:
(ns stub-http.example1
(:require [clojure.test :refer :all]
[stub-http.core :refer :all]
[cheshire.core :as json]
[clj-http.lite.client :as client]))
(deftest Example1
(with-routes!
{"/something" {:status 200 :content-type "application/json"
:body (json/generate-string {:hello "world"})}}
(let [response (client/get (str uri "/something"))
json-response (json/parse-string (:body response) true)]
(is (= "world" (:hello json-response))))))
我想知道在 Clojure 集成测试中是否有一种广泛使用的模式或解决方案用于将出站 HTTP 请求存根到第三方(la Ruby 的 webmock)。我希望能够在高级别(例如,在设置函数中)存根请求,而不必将我的每个测试包装在 (with-fake-http [] ...)
之类的东西中或不得不求助于依赖注入。
这是动态变量的好用例吗?我想我可以在设置步骤中进入有问题的命名空间,并将副作用函数设置为无害的匿名函数。然而,这感觉很笨拙,我不喜欢更改应用程序代码以适应我的测试的想法。 (它也不比上面提到的解决方案好多少。)
交换包含假函数的特定于测试的 ns 是否有意义?在我的测试中有没有一种干净的方法可以做到这一点?
你可以看到一个使用ring/compojure框架的好例子:
> lein new compojure sample
> cat sample/test/sample/handler_test.clj
(ns sample.handler-test
(:require [clojure.test :refer :all]
[ring.mock.request :as mock]
[sample.handler :refer :all]))
(deftest test-app
(testing "main route"
(let [response (app (mock/request :get "/"))]
(is (= (:status response) 200))
(is (= (:body response) "Hello World"))))
(testing "not-found route"
(let [response (app (mock/request :get "/invalid"))]
(is (= (:status response) 404)))))
更新
对于出站 http 调用,您可能会发现 with-redefs
有用:
(ns http)
(defn post [url]
{: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
本例中,原函数post
returns"Hello world"。在单元测试中,我们使用返回 "Goodbye world".
post
完整文档 is at ClojureDocs.
前阵子我也遇到过类似的情况,我找不到任何满足我需求的 Clojure 库,所以我创建了自己的库 Stub HTTP。使用示例:
(ns stub-http.example1
(:require [clojure.test :refer :all]
[stub-http.core :refer :all]
[cheshire.core :as json]
[clj-http.lite.client :as client]))
(deftest Example1
(with-routes!
{"/something" {:status 200 :content-type "application/json"
:body (json/generate-string {:hello "world"})}}
(let [response (client/get (str uri "/something"))
json-response (json/parse-string (:body response) true)]
(is (= "world" (:hello json-response))))))