2016-10-17 92 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