[elixir!#0019][訳]Phoenix WebSockets by Alex Jensenのテスト
テキスト
最近、Phoenixのwebsocketsを使ってゲームホールを作成する方法について発表しました.私たちのチームはテストを非常に重視しているので、今日は私たちが前に書いたwebsocketコードをテストする方法を紹介します.
準備作業
最近、Phoenixのwebsocketsを使ってゲームホールを作成する方法について発表しました.私たちのチームはテストを非常に重視しているので、今日は私たちが前に書いたwebsocketコードをテストする方法を紹介します.
準備作業
開始する前に、mix test
を実行し、デフォルトのテストを削除し、テスト中の小さな問題を解決する必要があります.テストを作成する前に、他のエラーメッセージがないことを望んでいます.次に、Phoenix generatorが自動的に生成するchannelテストをすべて削除します.最初から作成するからです.
Helpers
Phoenixはすでにあなたのプロジェクトにいくつかのサポートファイルを作成して、あなたは中でよく使うテスト関数を定義することができて、他の言語のtest_helper/spec_helper
に似ています.ここにはchannel test用のファイルtest/support/channel_case.ex
があります.後でコードを追加します.quote do ... end
構造に追加したコードは、各channel testモジュールによって参照されます.ここではMyAppのためにUserは別名を設定します.using do
quote do
...
alias MyApp.{Repo, User}
...
end
end
Lobby Channel Testの作成
テストの作成を開始します.まず、新しいファイルtest/channels/lobby_channel_test.exs
を作成します.defmodule MyApp.LobbyChannelTest do
use MyApp.ChannelCase
alias MyApp.LobbyChannel
test "give me a dot" do
assert 1 == 1
end
end
use MyApp.ChannelCase
ファイルからhelpersを導入するにはtest/support
が必要です.mix test
を実行します.すべてが正しい場合、テストに合格したというメッセージが表示されます.
Socket試験杭
テストでユーザーのsocket接続をシミュレートするのは、予想以上に簡単かもしれません.私たちのコードでは、web/channels/user_socket.ex
ファイルでチェックするtokenが必要です.チャンネルに接続されたsocketを直接作成できるので、検証する必要はありません.しかしながら、検証により得るcurrent_user
の付与値を設定する必要がある.current_user
のsocketを作成するには、次の方法を使用します.def create_user(username) do
%User{}
|> User.changeset(%{username: username, password: "passw0rd", password_confirmation: "passw0rd"})
|> Repo.insert
end
test "user receives the current list of users online" do
{:ok, user} = create_user("jerry")
{:ok, _, socket} =
socket("", %{current_user: user})
|> subscirbe_and_join(LobbyChannel, "game:lobby")
end
ここでは、所定のユーザ名を用いて新しいユーザを作成する関数を定義する.この関数はtest/support/channel_case.ex
ファイルにも定義できるが、ここに残しておく.ユーザを作成した後、Phoenixが導入した関数であるsocket
関数に渡す.これでこのソケットのassignsが設定されました.その後、socketとchannelモジュール、および加入する部屋名をsubscribe_and_join
関数に一括して入力.成功すると{:ok, response, socket}
に戻りますが、ロビーシステムから値を返すことはありませんので、_
を使用して無視します.
Assertions
ユーザーを作成してchannelに参加しましたが、現在のロビーの状態を受け取ったかどうかをどのように判断しますか?私たちが参加したchannelは、現在のユーザーを含む応答を返すのではなく、joinイベントの後にデータをブロードキャストします.Phoenixは、放送を確認するための関数assert_broadcast
を提供する.
チャンネルテストを実行すると、Phoenixはイベント名とデータを含む送信ごとのブロードキャストのリストを保存する.assert_broadcast
は、このリストで所望のブロードキャストを検索し、見つかったらtrueを返します.このassertionは、タイムアウト(assert_broadcast
関数の3番目のパラメータ)前に所望のブロードキャストが送信されなければ失敗する.ここで、assertが放送するイベントはlobby_update
で、["jerry"]
を含むusersが付属しています.test "user receives the current list of users online" do
{:ok, user} = create_user("jerry")
{:ok, _, socket} =
socket("", %{current_user: user})
|> subscribe_and_join(LobbyChannel, "game:lobby")
assert_broadcast "lobby_update", %{users: ["jerry"]}
end
クリーンアップ
このlobby_update
のテストは今合格できるはずですが、もう一つの小さな問題があります.ユーザが加入すると現在のユーザリストに追加され、離れると削除されますが、私たちは現在加入しているだけです.Phoenixが関数から離れることに感謝します.私たちはこのように使用することができます.test "user receives the current list of users online" do
{:ok, user} = create_user("jerry")
{:ok, _, socket} =
socket("", %{current_user: user})
|> subscribe_and_join(LobbyChannel, "game:lobby")
assert_broadcast "lobby_update", %{users: ["jerry"]}
leave socket
end
もう一人のHelper
続行する前に、別のhelper関数を作成してユーザーを作成し、「game:lobby」チャンネルに参加しましょう.後のテストでこの手順を繰り返す必要があるからです.def create_user_and_join_lobby(username) do
{:ok, user} = create_user(username)
socket("", %{current_user: user})
|> subscirbe_and_join(LobbyChannel, "game:lobby")
end
以前のテストを次のように変更できます.test "user receives the current list of users online" do
{:ok, _, socket} =
create_user_and_join_lobby("jerry")
assert_broadcast "lobby_update", %{users: ["jerry"]}
leave socket
end
ゲーム招待のテスト
ゲームの招待をテストするために、2人のユーザーを作成し、招待イベントをサーバに送信し、招待がユーザーに送信されているかどうかを確認します.test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
end
「game_invite」のコードを見に行くと、送信者とユーザー名を含むブロードキャストが発行されていますが、ブロードキャストがブロックされ、正しいユーザーにしか送信されません.ここでは、チェックしたいメッセージが放送されていないため、assert_broadcast
を使用することはできません.assert_push
を使用できます.test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
assert_push "game_invite", %{username: "bill"}
end
以上のコードを観察すると、username
キーが文字列であるか、原子であるかを知りたいかもしれません.通常、あなたのsockeはすべてのものをJSONに符号化してクライアントに送信します.これはすべて文字列になります.channelテストはchannelに対してより直接的な制御を持っているので、実際に受信したデータと完全に一致することを確保しなければならない.
すべてのソケットを離れたことを確認してください.test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
assert_push "game_invite", %{username: "bill"}
leave socket1
leave socket2
end
まとめ
Phoenixのwebsocketsをテストする方法を簡単に紹介した.最初はテストが怖いと思っていたかもしれませんが、実際には簡単で速いです.大規模なアプリケーションでは、強力なhelperを定義することが特に重要である.ExUnitのドキュメントのさまざまな機能を確認してください.
Phoenixはすでにあなたのプロジェクトにいくつかのサポートファイルを作成して、あなたは中でよく使うテスト関数を定義することができて、他の言語の
test_helper/spec_helper
に似ています.ここにはchannel test用のファイルtest/support/channel_case.ex
があります.後でコードを追加します.quote do ... end
構造に追加したコードは、各channel testモジュールによって参照されます.ここではMyAppのためにUserは別名を設定します.using do
quote do
...
alias MyApp.{Repo, User}
...
end
end
Lobby Channel Testの作成
テストの作成を開始します.まず、新しいファイルtest/channels/lobby_channel_test.exs
を作成します.defmodule MyApp.LobbyChannelTest do
use MyApp.ChannelCase
alias MyApp.LobbyChannel
test "give me a dot" do
assert 1 == 1
end
end
use MyApp.ChannelCase
ファイルからhelpersを導入するにはtest/support
が必要です.mix test
を実行します.すべてが正しい場合、テストに合格したというメッセージが表示されます.
Socket試験杭
テストでユーザーのsocket接続をシミュレートするのは、予想以上に簡単かもしれません.私たちのコードでは、web/channels/user_socket.ex
ファイルでチェックするtokenが必要です.チャンネルに接続されたsocketを直接作成できるので、検証する必要はありません.しかしながら、検証により得るcurrent_user
の付与値を設定する必要がある.current_user
のsocketを作成するには、次の方法を使用します.def create_user(username) do
%User{}
|> User.changeset(%{username: username, password: "passw0rd", password_confirmation: "passw0rd"})
|> Repo.insert
end
test "user receives the current list of users online" do
{:ok, user} = create_user("jerry")
{:ok, _, socket} =
socket("", %{current_user: user})
|> subscirbe_and_join(LobbyChannel, "game:lobby")
end
ここでは、所定のユーザ名を用いて新しいユーザを作成する関数を定義する.この関数はtest/support/channel_case.ex
ファイルにも定義できるが、ここに残しておく.ユーザを作成した後、Phoenixが導入した関数であるsocket
関数に渡す.これでこのソケットのassignsが設定されました.その後、socketとchannelモジュール、および加入する部屋名をsubscribe_and_join
関数に一括して入力.成功すると{:ok, response, socket}
に戻りますが、ロビーシステムから値を返すことはありませんので、_
を使用して無視します.
Assertions
ユーザーを作成してchannelに参加しましたが、現在のロビーの状態を受け取ったかどうかをどのように判断しますか?私たちが参加したchannelは、現在のユーザーを含む応答を返すのではなく、joinイベントの後にデータをブロードキャストします.Phoenixは、放送を確認するための関数assert_broadcast
を提供する.
チャンネルテストを実行すると、Phoenixはイベント名とデータを含む送信ごとのブロードキャストのリストを保存する.assert_broadcast
は、このリストで所望のブロードキャストを検索し、見つかったらtrueを返します.このassertionは、タイムアウト(assert_broadcast
関数の3番目のパラメータ)前に所望のブロードキャストが送信されなければ失敗する.ここで、assertが放送するイベントはlobby_update
で、["jerry"]
を含むusersが付属しています.test "user receives the current list of users online" do
{:ok, user} = create_user("jerry")
{:ok, _, socket} =
socket("", %{current_user: user})
|> subscribe_and_join(LobbyChannel, "game:lobby")
assert_broadcast "lobby_update", %{users: ["jerry"]}
end
クリーンアップ
このlobby_update
のテストは今合格できるはずですが、もう一つの小さな問題があります.ユーザが加入すると現在のユーザリストに追加され、離れると削除されますが、私たちは現在加入しているだけです.Phoenixが関数から離れることに感謝します.私たちはこのように使用することができます.test "user receives the current list of users online" do
{:ok, user} = create_user("jerry")
{:ok, _, socket} =
socket("", %{current_user: user})
|> subscribe_and_join(LobbyChannel, "game:lobby")
assert_broadcast "lobby_update", %{users: ["jerry"]}
leave socket
end
もう一人のHelper
続行する前に、別のhelper関数を作成してユーザーを作成し、「game:lobby」チャンネルに参加しましょう.後のテストでこの手順を繰り返す必要があるからです.def create_user_and_join_lobby(username) do
{:ok, user} = create_user(username)
socket("", %{current_user: user})
|> subscirbe_and_join(LobbyChannel, "game:lobby")
end
以前のテストを次のように変更できます.test "user receives the current list of users online" do
{:ok, _, socket} =
create_user_and_join_lobby("jerry")
assert_broadcast "lobby_update", %{users: ["jerry"]}
leave socket
end
ゲーム招待のテスト
ゲームの招待をテストするために、2人のユーザーを作成し、招待イベントをサーバに送信し、招待がユーザーに送信されているかどうかを確認します.test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
end
「game_invite」のコードを見に行くと、送信者とユーザー名を含むブロードキャストが発行されていますが、ブロードキャストがブロックされ、正しいユーザーにしか送信されません.ここでは、チェックしたいメッセージが放送されていないため、assert_broadcast
を使用することはできません.assert_push
を使用できます.test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
assert_push "game_invite", %{username: "bill"}
end
以上のコードを観察すると、username
キーが文字列であるか、原子であるかを知りたいかもしれません.通常、あなたのsockeはすべてのものをJSONに符号化してクライアントに送信します.これはすべて文字列になります.channelテストはchannelに対してより直接的な制御を持っているので、実際に受信したデータと完全に一致することを確保しなければならない.
すべてのソケットを離れたことを確認してください.test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
assert_push "game_invite", %{username: "bill"}
leave socket1
leave socket2
end
まとめ
Phoenixのwebsocketsをテストする方法を簡単に紹介した.最初はテストが怖いと思っていたかもしれませんが、実際には簡単で速いです.大規模なアプリケーションでは、強力なhelperを定義することが特に重要である.ExUnitのドキュメントのさまざまな機能を確認してください.
defmodule MyApp.LobbyChannelTest do
use MyApp.ChannelCase
alias MyApp.LobbyChannel
test "give me a dot" do
assert 1 == 1
end
end
テストでユーザーのsocket接続をシミュレートするのは、予想以上に簡単かもしれません.私たちのコードでは、
web/channels/user_socket.ex
ファイルでチェックするtokenが必要です.チャンネルに接続されたsocketを直接作成できるので、検証する必要はありません.しかしながら、検証により得るcurrent_user
の付与値を設定する必要がある.current_user
のsocketを作成するには、次の方法を使用します.def create_user(username) do
%User{}
|> User.changeset(%{username: username, password: "passw0rd", password_confirmation: "passw0rd"})
|> Repo.insert
end
test "user receives the current list of users online" do
{:ok, user} = create_user("jerry")
{:ok, _, socket} =
socket("", %{current_user: user})
|> subscirbe_and_join(LobbyChannel, "game:lobby")
end
ここでは、所定のユーザ名を用いて新しいユーザを作成する関数を定義する.この関数は
test/support/channel_case.ex
ファイルにも定義できるが、ここに残しておく.ユーザを作成した後、Phoenixが導入した関数であるsocket
関数に渡す.これでこのソケットのassignsが設定されました.その後、socketとchannelモジュール、および加入する部屋名をsubscribe_and_join
関数に一括して入力.成功すると{:ok, response, socket}
に戻りますが、ロビーシステムから値を返すことはありませんので、_
を使用して無視します.Assertions
ユーザーを作成してchannelに参加しましたが、現在のロビーの状態を受け取ったかどうかをどのように判断しますか?私たちが参加したchannelは、現在のユーザーを含む応答を返すのではなく、joinイベントの後にデータをブロードキャストします.Phoenixは、放送を確認するための関数assert_broadcast
を提供する.
チャンネルテストを実行すると、Phoenixはイベント名とデータを含む送信ごとのブロードキャストのリストを保存する.assert_broadcast
は、このリストで所望のブロードキャストを検索し、見つかったらtrueを返します.このassertionは、タイムアウト(assert_broadcast
関数の3番目のパラメータ)前に所望のブロードキャストが送信されなければ失敗する.ここで、assertが放送するイベントはlobby_update
で、["jerry"]
を含むusersが付属しています.test "user receives the current list of users online" do
{:ok, user} = create_user("jerry")
{:ok, _, socket} =
socket("", %{current_user: user})
|> subscribe_and_join(LobbyChannel, "game:lobby")
assert_broadcast "lobby_update", %{users: ["jerry"]}
end
クリーンアップ
このlobby_update
のテストは今合格できるはずですが、もう一つの小さな問題があります.ユーザが加入すると現在のユーザリストに追加され、離れると削除されますが、私たちは現在加入しているだけです.Phoenixが関数から離れることに感謝します.私たちはこのように使用することができます.test "user receives the current list of users online" do
{:ok, user} = create_user("jerry")
{:ok, _, socket} =
socket("", %{current_user: user})
|> subscribe_and_join(LobbyChannel, "game:lobby")
assert_broadcast "lobby_update", %{users: ["jerry"]}
leave socket
end
もう一人のHelper
続行する前に、別のhelper関数を作成してユーザーを作成し、「game:lobby」チャンネルに参加しましょう.後のテストでこの手順を繰り返す必要があるからです.def create_user_and_join_lobby(username) do
{:ok, user} = create_user(username)
socket("", %{current_user: user})
|> subscirbe_and_join(LobbyChannel, "game:lobby")
end
以前のテストを次のように変更できます.test "user receives the current list of users online" do
{:ok, _, socket} =
create_user_and_join_lobby("jerry")
assert_broadcast "lobby_update", %{users: ["jerry"]}
leave socket
end
ゲーム招待のテスト
ゲームの招待をテストするために、2人のユーザーを作成し、招待イベントをサーバに送信し、招待がユーザーに送信されているかどうかを確認します.test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
end
「game_invite」のコードを見に行くと、送信者とユーザー名を含むブロードキャストが発行されていますが、ブロードキャストがブロックされ、正しいユーザーにしか送信されません.ここでは、チェックしたいメッセージが放送されていないため、assert_broadcast
を使用することはできません.assert_push
を使用できます.test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
assert_push "game_invite", %{username: "bill"}
end
以上のコードを観察すると、username
キーが文字列であるか、原子であるかを知りたいかもしれません.通常、あなたのsockeはすべてのものをJSONに符号化してクライアントに送信します.これはすべて文字列になります.channelテストはchannelに対してより直接的な制御を持っているので、実際に受信したデータと完全に一致することを確保しなければならない.
すべてのソケットを離れたことを確認してください.test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
assert_push "game_invite", %{username: "bill"}
leave socket1
leave socket2
end
まとめ
Phoenixのwebsocketsをテストする方法を簡単に紹介した.最初はテストが怖いと思っていたかもしれませんが、実際には簡単で速いです.大規模なアプリケーションでは、強力なhelperを定義することが特に重要である.ExUnitのドキュメントのさまざまな機能を確認してください.
test "user receives the current list of users online" do
{:ok, user} = create_user("jerry")
{:ok, _, socket} =
socket("", %{current_user: user})
|> subscribe_and_join(LobbyChannel, "game:lobby")
assert_broadcast "lobby_update", %{users: ["jerry"]}
end
この
lobby_update
のテストは今合格できるはずですが、もう一つの小さな問題があります.ユーザが加入すると現在のユーザリストに追加され、離れると削除されますが、私たちは現在加入しているだけです.Phoenixが関数から離れることに感謝します.私たちはこのように使用することができます.test "user receives the current list of users online" do
{:ok, user} = create_user("jerry")
{:ok, _, socket} =
socket("", %{current_user: user})
|> subscribe_and_join(LobbyChannel, "game:lobby")
assert_broadcast "lobby_update", %{users: ["jerry"]}
leave socket
end
もう一人のHelper
続行する前に、別のhelper関数を作成してユーザーを作成し、「game:lobby」チャンネルに参加しましょう.後のテストでこの手順を繰り返す必要があるからです.def create_user_and_join_lobby(username) do
{:ok, user} = create_user(username)
socket("", %{current_user: user})
|> subscirbe_and_join(LobbyChannel, "game:lobby")
end
以前のテストを次のように変更できます.test "user receives the current list of users online" do
{:ok, _, socket} =
create_user_and_join_lobby("jerry")
assert_broadcast "lobby_update", %{users: ["jerry"]}
leave socket
end
ゲーム招待のテスト
ゲームの招待をテストするために、2人のユーザーを作成し、招待イベントをサーバに送信し、招待がユーザーに送信されているかどうかを確認します.test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
end
「game_invite」のコードを見に行くと、送信者とユーザー名を含むブロードキャストが発行されていますが、ブロードキャストがブロックされ、正しいユーザーにしか送信されません.ここでは、チェックしたいメッセージが放送されていないため、assert_broadcast
を使用することはできません.assert_push
を使用できます.test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
assert_push "game_invite", %{username: "bill"}
end
以上のコードを観察すると、username
キーが文字列であるか、原子であるかを知りたいかもしれません.通常、あなたのsockeはすべてのものをJSONに符号化してクライアントに送信します.これはすべて文字列になります.channelテストはchannelに対してより直接的な制御を持っているので、実際に受信したデータと完全に一致することを確保しなければならない.
すべてのソケットを離れたことを確認してください.test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
assert_push "game_invite", %{username: "bill"}
leave socket1
leave socket2
end
まとめ
Phoenixのwebsocketsをテストする方法を簡単に紹介した.最初はテストが怖いと思っていたかもしれませんが、実際には簡単で速いです.大規模なアプリケーションでは、強力なhelperを定義することが特に重要である.ExUnitのドキュメントのさまざまな機能を確認してください.
def create_user_and_join_lobby(username) do
{:ok, user} = create_user(username)
socket("", %{current_user: user})
|> subscirbe_and_join(LobbyChannel, "game:lobby")
end
test "user receives the current list of users online" do
{:ok, _, socket} =
create_user_and_join_lobby("jerry")
assert_broadcast "lobby_update", %{users: ["jerry"]}
leave socket
end
ゲームの招待をテストするために、2人のユーザーを作成し、招待イベントをサーバに送信し、招待がユーザーに送信されているかどうかを確認します.
test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
end
「game_invite」のコードを見に行くと、送信者とユーザー名を含むブロードキャストが発行されていますが、ブロードキャストがブロックされ、正しいユーザーにしか送信されません.ここでは、チェックしたいメッセージが放送されていないため、
assert_broadcast
を使用することはできません.assert_push
を使用できます.test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
assert_push "game_invite", %{username: "bill"}
end
以上のコードを観察すると、
username
キーが文字列であるか、原子であるかを知りたいかもしれません.通常、あなたのsockeはすべてのものをJSONに符号化してクライアントに送信します.これはすべて文字列になります.channelテストはchannelに対してより直接的な制御を持っているので、実際に受信したデータと完全に一致することを確保しなければならない.すべてのソケットを離れたことを確認してください.
test "user receives an invite" do
{:ok, _, socket1} =
create_user_and_join_lobby("bill")
{:ok, _, socket2} =
create_user_and_join_lobby("will")
push socket1, "game_invite", %{"username" => "will"}
assert_push "game_invite", %{username: "bill"}
leave socket1
leave socket2
end