如何使用 ring.mock.request 模拟 PUT 请求
How do I mock a PUT request using ring.mock.request
如何通过这个测试:
(ns imp-rest.parser-test-rest
(:require [clojure.test :refer :all])
(:require [ring.mock.request :as mock] )
(:require [imp-rest.web :as w]))
(deftest test-parser-rest
(testing "put settings"
(w/app
(mock/request :put "/settings/coordinateName" "FOO" ))
(let [response (w/app (mock/request :get "/settings"))]
(println response )
(is (= (get (:body response) :coordinateName) "FOO")))))
它失败了:
FAIL in (test-parser-rest) (parser_test_rest.clj:30)
put settings
expected: (= (get (:body response) :coordinateName) "FOO")
actual: (not (= nil "FOO"))
这是我的处理程序:
(ns imp-rest.web
(:use compojure.core)
(:use ring.middleware.json-params)
(:require [clj-json.core :as json])
(:require [ring.util.response :as response])
(:require [compojure.route :as route])
(:require [imp-rest.settings :as s]))
(defn json-response [data & [status]]
{:status (or status 200)
:headers {"Content-Type" "application/json"}
:body (json/generate-string data)})
(defroutes handler
(GET "/settings" []
(json-response (s/get-settings)))
(GET "/settings/:id" [id]
(json-response (s/get-setting id)))
(PUT "/settings" [id value]
(json-response (s/put-setting id value)))
(route/not-found "Page not found") )
(def app
(-> handler
wrap-json-params))
公开这张地图(设置):
(ns imp-rest.settings)
(def settings
(atom
{:coordinateName nil
:burnin nil
:nslices nil
:mrsd nil
}))
(defn get-settings []
@settings)
(defn get-setting [id]
(@settings (keyword id)))
(defn put-setting [id value]
(swap! settings assoc (keyword id) value)
value)
和入口点:
(ns imp-rest.core
(:use ring.adapter.jetty)
(:require [imp-rest.web :as web]))
(defn -main
"Entry point"
[& args]
(do
(run-jetty #'web/app {:port 8080})
);END;do
);END: main
现在,当我 'lein run' 时,我可以提出这样的(有效)请求:
curl -X PUT -H "Content-Type: application/json" \
-d '{"id" : "coordinateName", "value" : "FOO"}' \
http://localhost:8080/settings
这就是我试图通过测试模拟的内容。任何帮助表示赞赏。
如果你想在你的 PUT /settings/:id
路由接受体中使用 {"value": "..."}
格式的 :id
,你需要更改你的路由定义:
(defroutes handler
(GET "/settings" []
(json-response (s/get-settings)))
(GET "/settings/:id" [id]
(json-response (s/get-setting id)))
(PUT "/settings/:id" [id value]
(json-response (s/put-setting id value)))
(route/not-found "Page not found"))
并更改您在测试中调用 PUT
端点的方式:
(w/app
(-> (mock/request
:put
"/settings/coordinateName"
(json/generate-string {:value "FOO"}))
(mock/content-type "application/json")))
改变了什么?
:id
在您的 PUT
URL 路由定义中 (/settings
-> /settings/:id
)
- 您的
PUT
请求没有发送正确的请求和内容类型。
如果你想要 PUT /settings
路由期望 {"id": "...", "value": "..."}
请求主体,那么你需要更改创建模拟请求的方式:
(w/app
(-> (mock/request
:put
"/settings"
(json/generate-string {:id "coordinateName" :value "FOO"}))
(mock/content-type "application/json"))
您的 curl 请求在 PUT 请求的正文中将参数指定为 JSON,但您的模拟请求尝试使用 URL 参数。
有两种解决方法:
- compojure 可以自动转换参数,但前提是存在相关的中间件——您已将
wrap-json-params
添加到处理程序,但缺少 wrap-params
。 Piotrek Bzdyl 的回答相当于在复合路线中明确这些参数。
- 或者,您可以使用
request.mock.body
. 在模拟请求的正文中添加 ID/value 对作为 JSON
如何通过这个测试:
(ns imp-rest.parser-test-rest
(:require [clojure.test :refer :all])
(:require [ring.mock.request :as mock] )
(:require [imp-rest.web :as w]))
(deftest test-parser-rest
(testing "put settings"
(w/app
(mock/request :put "/settings/coordinateName" "FOO" ))
(let [response (w/app (mock/request :get "/settings"))]
(println response )
(is (= (get (:body response) :coordinateName) "FOO")))))
它失败了:
FAIL in (test-parser-rest) (parser_test_rest.clj:30)
put settings
expected: (= (get (:body response) :coordinateName) "FOO")
actual: (not (= nil "FOO"))
这是我的处理程序:
(ns imp-rest.web
(:use compojure.core)
(:use ring.middleware.json-params)
(:require [clj-json.core :as json])
(:require [ring.util.response :as response])
(:require [compojure.route :as route])
(:require [imp-rest.settings :as s]))
(defn json-response [data & [status]]
{:status (or status 200)
:headers {"Content-Type" "application/json"}
:body (json/generate-string data)})
(defroutes handler
(GET "/settings" []
(json-response (s/get-settings)))
(GET "/settings/:id" [id]
(json-response (s/get-setting id)))
(PUT "/settings" [id value]
(json-response (s/put-setting id value)))
(route/not-found "Page not found") )
(def app
(-> handler
wrap-json-params))
公开这张地图(设置):
(ns imp-rest.settings)
(def settings
(atom
{:coordinateName nil
:burnin nil
:nslices nil
:mrsd nil
}))
(defn get-settings []
@settings)
(defn get-setting [id]
(@settings (keyword id)))
(defn put-setting [id value]
(swap! settings assoc (keyword id) value)
value)
和入口点:
(ns imp-rest.core
(:use ring.adapter.jetty)
(:require [imp-rest.web :as web]))
(defn -main
"Entry point"
[& args]
(do
(run-jetty #'web/app {:port 8080})
);END;do
);END: main
现在,当我 'lein run' 时,我可以提出这样的(有效)请求:
curl -X PUT -H "Content-Type: application/json" \
-d '{"id" : "coordinateName", "value" : "FOO"}' \
http://localhost:8080/settings
这就是我试图通过测试模拟的内容。任何帮助表示赞赏。
如果你想在你的 PUT /settings/:id
路由接受体中使用 {"value": "..."}
格式的 :id
,你需要更改你的路由定义:
(defroutes handler
(GET "/settings" []
(json-response (s/get-settings)))
(GET "/settings/:id" [id]
(json-response (s/get-setting id)))
(PUT "/settings/:id" [id value]
(json-response (s/put-setting id value)))
(route/not-found "Page not found"))
并更改您在测试中调用 PUT
端点的方式:
(w/app
(-> (mock/request
:put
"/settings/coordinateName"
(json/generate-string {:value "FOO"}))
(mock/content-type "application/json")))
改变了什么?
:id
在您的PUT
URL 路由定义中 (/settings
->/settings/:id
)- 您的
PUT
请求没有发送正确的请求和内容类型。
如果你想要 PUT /settings
路由期望 {"id": "...", "value": "..."}
请求主体,那么你需要更改创建模拟请求的方式:
(w/app
(-> (mock/request
:put
"/settings"
(json/generate-string {:id "coordinateName" :value "FOO"}))
(mock/content-type "application/json"))
您的 curl 请求在 PUT 请求的正文中将参数指定为 JSON,但您的模拟请求尝试使用 URL 参数。
有两种解决方法:
- compojure 可以自动转换参数,但前提是存在相关的中间件——您已将
wrap-json-params
添加到处理程序,但缺少wrap-params
。 Piotrek Bzdyl 的回答相当于在复合路线中明确这些参数。 - 或者,您可以使用
request.mock.body
. 在模拟请求的正文中添加 ID/value 对作为 JSON