檢視原始碼 Phoenix.ConnTest (Phoenix v1.7.14)
測試 Phoenix 端點和連線相關輔助功能的便利性。
你可能想使用這個模組把它加入到你的 ExUnit.CaseTemplate
中。使用後,這個模組將自動匯入此處定義的所有函數以及 Plug.Conn
中的函數。
端點測試
通常 Phoenix.ConnTest
會針對端點運作。那是測試任何路徑都會傳送至路由器的方式
@endpoint MyAppWeb.Endpoint
test "says welcome on the home page" do
conn = get(build_conn(), "/")
assert conn.resp_body =~ "Welcome!"
end
test "logs in" do
conn = post(build_conn(), "/login", [username: "john", password: "doe"])
assert conn.resp_body =~ "Logged in!"
end
@endpoint
模組屬性包含正在測試的端點,最常見的是應用程式端點本身。如果你正在使用由 Phoenix 生成的 MyApp.ConnCase,它會自動為你設定。
與路徑和控制器中一樣,連線是測試中的主要抽象化。 build_conn()
會回傳一個新的連線,此模組中的函數可以在傳送至端點前用來操作連線。
例如,可以為 json 要求設定接受標頭如下所示
build_conn()
|> put_req_header("accept", "application/json")
|> get("/")
你也可以建立自己的輔助函數,例如 json_conn()
,它使用了 build_conn/0
和 put_req_header/3
,這樣就不必在你的測試中一直重複連線設定。
控制器測試
這個模組中的函數也可以用於控制器測試。雖然端點測試優於控制器測試,特別是因為 Phoenix 中的控制器在你的網域和你的檢視之間扮演整合角色,對控制器的單元測試可能在某些情況下會有幫助。
對於此類情況,你需要將 @endpoint
屬性設定為你的控制器,並傳入表示傳送動作的原子
@endpoint MyAppWeb.HomeController
test "says welcome on the home page" do
conn = get(build_conn(), :index)
assert conn.resp_body =~ "Welcome!"
end
請記住,一旦設定 @endpoint
變數,後續設定後的所有測試都會受到影響。
檢視測試
其他狀況下,您可能會測試檢視或其他層,需要連線才能處理。對於此類案例,可以使用 build_conn/3
程式碼輔助工具建立連線
MyApp.UserView.render("hello.html", conn: build_conn(:get, "/"))
而 build_conn/0
傳回未載有請求資訊的連線,build_conn/3
傳回載有已填妥指定請求資訊的連線。
回收
瀏覽器實作使用 Cookie 的儲存。在回應中設定 cookie 時,瀏覽器會儲存它,並在下一個請求中傳送它。
為了模擬此行為,此模組提供了**回收**的概念。recycle/1
函數會收到一個連線並傳回一個新的連線,類似於 build_conn/0
傳回的連線,但包含之前連線中定義為請求標頭的所有回應 Cookie。在測試需要 Cookie 或階段才能運作的巨量路由時,這很有用。
請記住 Phoenix 會在發送之間自動回收連線。這通常大部分時間都能順利運作,但是如果您修改連線在下一次發送之前修改連線,它可能會捨棄資訊
# No recycling as the connection is fresh
conn = get(build_conn(), "/")
# The connection is recycled, creating a new one behind the scenes
conn = post(conn, "/login")
# We can also recycle manually in case we want custom headers
conn =
conn
|> recycle()
|> put_req_header("x-special", "nice")
# No recycling as we did it explicitly
conn = delete(conn, "/logout")
回收也會回收「接受」和「授權」標頭,以及對等資料資訊。
摘要
功能
斷言錯誤已被封裝,並以指定狀態傳送。
建立用於未來請求的連線。
建立用於未來請求的連線,採用預設方法、路徑和主體。
呼叫端點和路由器管線。
呼叫目前路由的端點和路由器管線。
呼叫端點和指定的路由器管線。
清除快閃儲存。
刪除請求 Cookie。
確保連線已回收,如果還沒。
提取快閃儲存。
取得整個快閃儲存。
從快閃儲存取得給定的金鑰。
發送到目前的端點。
斷言給定的狀態碼、我們有 html 回應,如果設定或傳送 回應主體,則傳回它。
初始化一個專門用於測試的會話。
斷言給定的狀態碼、我們有 json 回應,如果設定或傳送 解碼的 JSON 回應,則傳回它。
發送到目前的端點。
發送到目前的端點。
傳回 %Plug.Conn{}
路由器的 URL 相符參數。
發送到目前的端點。
發送到目前的端點。
將給定的值放置於快閃儲存中的金鑰下方。
放置一個要求 cookie。
傳回連線被重新導向到的 URL 相符參數。
傳回從給定的重新導向回應中的位置標頭。
斷言給定的狀態碼,如果設定或傳送 回應主體,則傳回它。
傳回內容類型,只要與給定的格式相符。
斷言給定的狀態碼、我們有文字回應,如果設定或傳送 回應主體,則傳回它。
發送到目前的端點。
函式
斷言錯誤已被封裝,並以指定狀態傳送。
對於測試預期會引發錯誤並回應由 HTTP 狀態包裝,通常由 MyAppWeb.ErrorHTML 檢視呈現內容的動作很有用。
此函式接受一個狀態,可以是整數 HTTP 狀態或原子,例如 500
或 :internal_server_error
。允許使用的原子清單在 Plug.Conn.Status
中。如果引發錯誤,將傳回封裝回應的 3 元組,與回應的狀態、標頭和主體相符
{500, [{"content-type", "text/html"} | _], "Internal Server Error"}
範例
assert_error_sent :internal_server_error, fn ->
get(build_conn(), "/broken/route")
end
response = assert_error_sent 500, fn ->
get(build_conn(), "/broken/route")
end
assert {500, [_h | _t], "Internal Server Error"} = response
可將此用於測試路徑導致錯誤,且錯誤已由 Plug.Status
協定轉換成特定回應,例如 Ecto.NoResultsError
assert_error_sent :not_found, fn ->
get(build_conn(), "/something-that-raises-no-results-error")
end
注意:對於不會引發錯誤,而是傳回狀態的路徑,你應該直接測試回應
conn = get(build_conn(), "/users/not-found")
assert response(conn, 404)
@spec build_conn() :: Plug.Conn.t()
建立用於未來請求的連線。
建立用於未來請求的連線,採用預設方法、路徑和主體。
當需要特定連線來測試外掛程式或某個特定功能時,這很有用。
@spec bypass_through(Plug.Conn.t()) :: Plug.Conn.t()
呼叫端點和路由器管線。
用於單元測試外掛程式,其中端點和/或路由器管線外掛程式是正確設定所必需的。
請注意,以下範例在 bypass_through
後面使用 get("/")
。若要執行外掛程式管線,您必須針對路由器發出請求。您通常只要針對根路徑傳送 GET 請求即可,但您也可以指定管線可能運作在不同的方法或路徑上。
範例
例如,假設您要獨立測試認證外掛程式,但您需要呼叫端點外掛程式和路由器管線來設定與工作階段和快閃相關的相依性。其中一個選項是呼叫使用適當管線的現有路由。您可以透過將連線和路由器名稱傳遞給 bypass_through
來這麼做
conn =
conn
|> bypass_through(MyAppWeb.Router)
|> get("/some_url")
|> MyApp.RequireAuthentication.call([])
assert conn.halted
您也可以指定要執行的管線。
conn =
conn
|> bypass_through(MyAppWeb.Router, [:browser])
|> get("/")
|> MyApp.RequireAuthentication.call([])
assert conn.halted
或者,您只能呼叫端點外掛程式
conn =
conn
|> bypass_through()
|> get("/")
|> MyApp.RequireAuthentication.call([])
assert conn.halted
@spec bypass_through(Plug.Conn.t(), module()) :: Plug.Conn.t()
呼叫目前路由的端點和路由器管線。
請參閱 bypass_through/1
。
@spec bypass_through(Plug.Conn.t(), module(), atom() | list()) :: Plug.Conn.t()
呼叫端點和指定的路由器管線。
請參閱 bypass_through/1
。
@spec clear_flash(Plug.Conn.t()) :: Plug.Conn.t()
清除快閃儲存。
發送到目前的端點。
有關詳細資訊,請參閱 dispatch/5
。
發送到目前的端點。
有關詳細資訊,請參閱 dispatch/5
。
@spec delete_req_cookie(Plug.Conn.t(), binary()) :: Plug.Conn.t()
刪除請求 Cookie。
將連線發送到指定的端點。
當透過 get/3
、post/3
和相關函式呼叫時,端點會自動從 @endpoint
模組屬性中擷取,否則必須將它指定為參數。
將使用提供的 method
、path_or_action
和 params_or_body
來設定連線。
如果 path_or_action
是字串,它會被視為請求路徑並如此儲存在連線中。如果是原子,則假設它是一個動作,並且連線會傳送至指定的動作。
參數和主體
這個函式以及 get/3
、post/3
和相關函式接受請求主體或參數做為最後一個參數
get(build_conn(), "/", some: "param")
get(build_conn(), "/", "some=param&url=encoded")
允許的值為
nil
表示沒有主體二進位檔,包含請求主體。在這種情況下,必須將
:headers
作為選項,並設定內容類型。清單或地圖,包含參數,它會自動將內容類型設定為多部分式。清單或地圖可以包含其他清單或地圖,所有項目都會標準化為字串鍵。
結構,不同於其他地圖,結構會照原樣傳遞,而不會標準化其項目。
@spec ensure_recycled(Plug.Conn.t()) :: Plug.Conn.t()
確保連線已回收,如果還沒。
請參閱 recycle/1
以了解更多資訊。
@spec fetch_flash(Plug.Conn.t()) :: Plug.Conn.t()
提取快閃儲存。
發送到目前的端點。
有關詳細資訊,請參閱 dispatch/5
。
@spec get_flash(Plug.Conn.t()) :: map()
取得整個快閃儲存。
@spec get_flash(Plug.Conn.t(), term()) :: term()
從快閃儲存取得給定的金鑰。
發送到目前的端點。
有關詳細資訊,請參閱 dispatch/5
。
@spec html_response(Plug.Conn.t(), status :: integer() | atom()) :: String.t()
斷言給定的狀態碼、我們有 html 回應,如果設定或傳送 回應主體,則傳回它。
範例
assert html_response(conn, 200) =~ "<html>"
@spec init_test_session(Plug.Conn.t(), map() | keyword()) :: Plug.Conn.t()
初始化一個專門用於測試的會話。
@spec json_response(Plug.Conn.t(), status :: integer() | atom()) :: term()
斷言給定的狀態碼、我們有 json 回應,如果設定或傳送 解碼的 JSON 回應,則傳回它。
範例
body = json_response(conn, 200)
assert "can't be blank" in body["errors"]
發送到目前的端點。
有關詳細資訊,請參閱 dispatch/5
。
發送到目前的端點。
有關詳細資訊,請參閱 dispatch/5
。
@spec path_params(Plug.Conn.t(), String.t()) :: map()
傳回 %Plug.Conn{}
路由器的 URL 相符參數。
可從傳回的網址中擷取路徑參數,例如 Phoenix.LiveViewTest
中會傳回重導的結果。
範例
assert {:error, {:redirect, %{to: "/posts/123" = to}}} = live(conn, "/path")
assert %{id: "123"} = path_params(conn, to)
發送到目前的端點。
有關詳細資訊,請參閱 dispatch/5
。
發送到目前的端點。
有關詳細資訊,請參閱 dispatch/5
。
@spec put_flash(Plug.Conn.t(), term(), term()) :: Plug.Conn.t()
將給定的值放置於快閃儲存中的金鑰下方。
@spec put_req_cookie(Plug.Conn.t(), binary(), binary()) :: Plug.Conn.t()
放置一個要求 cookie。
@spec recycle(Plug.Conn.t(), [String.t()]) :: Plug.Conn.t()
回收連線。
重用會接收連線,並根據指定的連線傳回包含 cookie 及相關資訊的新連線。
這類似瀏覽器的行為,會將回應中傳回的 cookie 用於後續要求。
預設情況下只會重用標頭「accept」、「accept-language」和「authorization」。不過,可以指定自訂的標頭集合,只要將代表標頭名稱的字串清單傳遞給函式作為第二個參數即可。
請注意,除非連線已經重用,否則在呼叫端點時 recycle/1
會自動呼叫。
@spec redirected_params(Plug.Conn.t(), status :: non_neg_integer()) :: map()
傳回連線被重新導向到的 URL 相符參數。
採用上一個要求中與路由匹配的已提供 %Plug.Conn{}
。若回應的位置標頭未設定,或回應不符合重導狀態代碼 (預設為 302),則會發生錯誤。
範例
assert redirected_to(conn) =~ "/posts/123"
assert %{id: "123"} = redirected_params(conn)
assert %{id: "123"} = redirected_params(conn, 303)
@spec redirected_to(Plug.Conn.t(), status :: non_neg_integer()) :: String.t()
傳回從給定的重新導向回應中的位置標頭。
若回應不符合重導狀態代碼,則會發生錯誤 (預設為 302)。
範例
assert redirected_to(conn) =~ "/foo/bar"
assert redirected_to(conn, 301) =~ "/foo/bar"
assert redirected_to(conn, :moved_permanently) =~ "/foo/bar"
@spec response(Plug.Conn.t(), status :: integer() | atom()) :: binary()
斷言給定的狀態碼,如果設定或傳送 回應主體,則傳回它。
範例
conn = get(build_conn(), "/")
assert response(conn, 200) =~ "hello world"
@spec response_content_type(Plug.Conn.t(), atom()) :: String.t()
傳回內容類型,只要與給定的格式相符。
範例
# Assert we have an html response with utf-8 charset
assert response_content_type(conn, :html) =~ "charset=utf-8"
@spec text_response(Plug.Conn.t(), status :: integer() | atom()) :: String.t()
斷言給定的狀態碼、我們有文字回應,如果設定或傳送 回應主體,則傳回它。
範例
assert text_response(conn, 200) =~ "hello"
發送到目前的端點。
有關詳細資訊,請參閱 dispatch/5
。