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

 Смежные вопросы

  • Нет связанных вопросов^_^