我想用ring.mock
编写一个简单的POST请求测试 - 是这样的:
(testing "id post route"
(let [response (app (mock/request :post "/" {:id "Foo"}))]
(is (= 302 (:status response)))))
然而,由于我用的是wrap-csrf
中间件,我收到了403个状态响应,因为我不提供防伪标记。
有没有写与ring.mock
POST测试,没有禁用wrap-csrf
中间件的方法吗?
你要什么测试?这不是从你的问题清楚,为什么你不应该禁用防伪中间件都还不清楚。
handler
逻辑对其进行测试,而不捆绑“基础设施”的中间件。还有,用嘲讽的防伪中间件,如果你可以没有它在测试中应用到您的处理功能,问题消失没有意义的。首先,我想回应一些关于此地另一篇文章的方法和推理的要点:
app
它代表了整个应用程序,但你可以在命令如果需要直接测试端点绕过CSRF。这将允许您测试给定的终点,但不考了CSRF保护工作正常。假设上述情况,你可能需要测试的登录过程是否正常工作和CSRF集成。下面的测试助手应该帮助你沿着这条路径:
(ns myapp.test.handler-test
(:require [clojure.test :refer :all]
[ring.mock.request :refer [request]]
[net.cgrand.enlive-html :as html]
[myapp.handler :refer [app]]))
(defn get-session
"Given a response, grab out just the key=value of the ring session"
[resp]
(let [headers (:headers resp)
cookies (get headers "Set-Cookie")
session-cookies (first (filter #(.startsWith % "ring-session") cookies))
session-pair (first (clojure.string/split session-cookies #";"))]
session-pair))
(defn get-csrf-field
"Given an HTML response, parse the body for an anti-forgery input field"
[resp]
(-> (html/select (html/html-snippet (:body resp)) [:input#__anti-forgery-token])
first
(get-in [:attrs :value])))
(defn get-login-session!
"Fetch a login page and return the associated session and csrf token"
[]
(let [resp (app (request :get "/login"))]
{:session (get-session resp)
:csrf (get-csrf-field resp)}))
(defn login!
"Login a user given a username and password"
[username password]
(let [{:keys [csrf session]} (get-login-session!)
req (-> (request :post "/login")
(assoc :headers {"cookie" session})
(assoc :params {:username username
:password password})
(assoc :form-params {"__anti-forgery-token" csrf}))]
(app req)
session))
在上文中,我假设/login
页面使用__anti-forgery-token
隐藏的输入和要测试的此。你也可以考虑把会话数据的CSRF令牌,这使得它更容易与像curl
可以从一个响应,为连续请求使用的文件保存会话数据的工具来测试。
由于我拉令牌出了HTML的身体,我决定使用enlive
,这样我可以使用CSS选择器来定义在那里我从一个简单的和声明的方式拉这个数据。
为了利用上述的,你可以打电话login!
,然后用它要与相同的会话进行身份验证的连续请求,如返回会话数据:
(deftest test-home-page-authentication
(testing "authenticated response"
(let [session (login! "bob" "bob")
request (-> (request :get "/")
(assoc :headers {"cookie" session}))]
(is (= 200 (:status (app request)))))))
这里假设你有Bob的用户名/密码和鲍勃在任何权威性的后端使用的是成立。你可能会需要有一个创建该用户在此之前登录过程将工作一个用户名/密码设置步骤。
我们可以使用csrf
在测试中禁用(assoc site-defaults :security false)
。完整的代码是这样的:
; Create a copy of testing app in utilities.testing
; by wrapping handler with testing middlewares
(ns utilities.testing
(:require [your-web-app.handler :refer [path-handler]]
[ring.middleware.defaults :refer [wrap-defaults site-defaults]]))
; Disabling CSRF for testing
(def app
(-> path-handler
(wrap-defaults (assoc site-defaults :security false))))
现在你可以使用这个应用程序在测试中
(ns users.views-test
(:require [utilities.testing :refer [app]]
;...
))
;...
(testing "id post route"
(let [response (app (mock/request :post "/" {:id "Foo"}))]
(is (= 302 (:status response)))))