【问题标题】:How do I mock a PUT request using ring.mock.request如何使用 ring.mock.request 模拟 PUT 请求
【发布时间】:2016-04-01 07:38:53
【问题描述】:

如何让这个测试通过:

(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

这是我试图用测试来模拟的。任何帮助表示赞赏。

【问题讨论】:

  • URL 中的PUT /settings work? Does it have id` 应该如何或作为 JSON 请求正文的一部分?
  • 理想情况下按 URL 标识,例如浏览到localhost:8080/settings/coordinateName 给出“FOO”。
  • 我修复了你的非惯用格式,尤其是。关于括号的位置。可能您使用的编辑器无法帮助您查看代码的结构并迷失在括号中。尝试使用一个可以帮助您的。还要尝试坚持通常的格式约定(例如右括号前没有空格),以便人们更容易看到结构 - 您很快就会习惯于自己查看没有括号的结构。

标签: clojure mocking put ring


【解决方案1】:

如果你想在你的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")))

改变了什么?

  1. :id 在您的 PUT URL 路由定义中 (/settings -> /settings/:id)
  2. 您的 PUT 请求未发送正确的请求和内容类型。

如果您希望有一个 PUT /settings 路由期望 {"id": "...", "value": "..."} 请求正文,那么您需要更改创建模拟请求的方式:

(w/app 
  (-> (mock/request
        :put
        "/settings"
        (json/generate-string {:id "coordinateName" :value "FOO"}))
      (mock/content-type "application/json"))

【讨论】:

  • 非常非常有帮助,谢谢。最后一个代码位中缺少括号。
  • ring-mock 提供ring.mock.request/json-body 功能,因此无需手动将正文编码为JSON并将Content-Type标头设置为application/json
【解决方案2】:

您的 curl 请求将参数指定为 PUT 请求正文中的 JSON,但您的模拟请求尝试使用 URL 参数。

有两种方法可以解决这个问题:

  • compojure 可以自动转换参数,但只有在存在相关中间件时——您已将wrap-json-params 添加到您的处理程序中,但您缺少wrap-params。 Piotrek Bzdyl 的回答是让这些参数在复合路由中显式化。
  • 或者,您可以使用 request.mock.body 将 ID/值对作为 JSON 添加到模拟请求的正文中。

【讨论】:

    猜你喜欢
    • 2013-09-10
    • 2012-01-08
    • 2021-10-02
    • 1970-01-01
    • 2021-01-29
    • 2016-11-27
    • 1970-01-01
    • 2019-11-14
    • 2019-12-12
    相关资源
    最近更新 更多