2016-10-17 61 views
1

我使用http-kit作为wrap-json-body来自ring.middleware.json的服务器,以获取从客户端发送的字符串化JSON内容作为请求主体。我core.clj是:如何使用环模拟请求模拟测试POST请求与身体为JSON?

; core.clj 
; .. 
(defroutes app-routes 
    (POST "/sign" {body :body} (sign body))) 

(def app (site #'app-routes)) 

(defn -main [] 
    (-> app 
     (wrap-reload) 
     (wrap-json-body {:keywords? true :bigdecimals? true}) 
     (run-server {:port 8080})) 
    (println "Server started.")) 

当我运行使用lein run方法正常工作的服务器。我将JSON字符串化并从客户端发送。标志方法正确得到json,如{"abc": 1}

问题是在模拟测试过程中。 sig n方法得到一个ByteArrayInputStream和我使用json/generate-string转换为在这种情况下失败的字符串。我试图在wrap-json-body包装处理程序,但它不起作用。下面是我的测试情况下,我尝试了core_test.clj

; core_test.clj 
; .. 
(deftest create-sign-test 
    (testing "POST sign" 
     (let [response 
      (wrap-json-body (core/app (mock/request :post "/sign" "{\"username\": \"jane\"}")) 
      {:keywords? true :bigdecimals? true})] 
      (is (= (:status response) 200)) 
      (println response)))) 

(deftest create-sign-test1 
    (testing "POST sign1" 
     (let [response (core/app (mock/request :post "/sign" "{\"username\": \"jane\"}"))] 
      (is (= (:status response) 200)) 
      (println response)))) 

(deftest create-sign-test2 
    (testing "POST sign2" 
     (let [response (core/app (-> (mock/body (mock/request :post "/sign") 
             (json/generate-string {:user 1})) 
            (mock/content-type "application/json")))] 
      (is (= (:status response) 200)) 
      (println response)))) 

(deftest create-sign-test3 
(testing "POST sign3" 
    (let [response 
     (wrap-json-body (core/app (mock/request :post "/sign" {:headers {"content-type" "application/json"} 
        :body "{\"foo\": \"bar\"}"})) 
     {:keywords? true :bigdecimals? true})] 
     (is (= (:status response) 200)) 
     (println response)))) 

所有的失败,出现以下错误:

Uncaught exception, not in assertion. 
expected: nil 
    actual: com.fasterxml.jackson.core.JsonGenerationException: Cannot JSON encode object of class: class java.io.ByteArrayInputStream: [email protected] 

我如何传递一个JSON字符串作为身体的方法在环模拟测试?

回答

2

你的代码有三个问题。

  1. 您的测试不换你的应用程序处理程序wrap-json-body所以它有可能不能正确解析请求主体在你的处理器。您需要先将app包装在wrap-json-body中,然后用您的模拟请求进行调用。 (你也可以有你的app处理程序,而不是已经被包裹在你的主要功能和测试它环绕两个)

    (let [handler (-> app (wrap-json-body {:keywords? true :bigdecimals? true})] 
        (handler your-mock-request)) 
    
  2. 你的模拟请求不包括适当的内容类型和wrap-json-body不会解析您的请求正文给JSON。这就是为什么你的sign函数得到ByteArrayInputStream而不是解析的JSON。你需要的内容类型添加到您的模拟要求:

    (let [request (-> (mock/request :post "/sign" "{\"username\": \"jane\"}") 
            (mock/content-type "application/json"))] 
        (handler request)) 
    
  3. 确认您sign功能使用JSON返回响应地图中体字符串。如果它将响应主体创建为输入流,则需要将其解析为测试函数。下面我使用cheshire解析它(转换JSON键关键字):

    (cheshire.core/parse-stream (-> response :body clojure.java.io/reader) keyword) 
    

此外代替手工编写JSON请求主体可以用柴您的数据编码成JSON字符串:

(let [json-body (cheshire.core/generate-string {:username "jane"})] 
    ...) 

这些变化应该可以正常工作,就像在我稍微修改例如:

(defroutes app-routes 
    (POST "/echo" {body :body} 
    {:status 200 :body body})) 

(def app (site #'app-routes)) 

(let [handler (-> app (wrap-json-body {:keywords? true :bigdecimals? true})) 
     json-body (json/generate-string {:username "jane"}) 
     request (-> (mock/request :post "/echo" json-body) 
        (mock/content-type "application/json")) 
     response (handler request)] 
    (is (= (:status response) 200)) 
    (is (= (:body response) {:username "jane"}))) 
+0

非常感谢你! 'sign'方法正确地获取JSON。我一直在努力几个小时才能做到这一点。 – boring