翻訳者から: 「エリクサーとフェニックスは、最新のWeb開発が進んでいる好例です。 すでにこれらのツールは、Webアプリケーションのリアルタイムテクノロジーへの質の高いアクセスを提供します。 対話性が向上したサイト、マルチユーザーブラウザーゲーム、マイクロサービスは、これらの技術がうまく機能する分野です。 以下は、Phoenixフレームワークでの開発の詳細な側面を説明する一連の11の記事の翻訳です。ブログエンジンのような些細なことのように思えます。 しかし、急いでつまずかないでください。特に記事がエリクサーに注意を払うか、彼のフォロワーになるように促す場合、それは本当に興味深いでしょう。」
このパートでは、チャネルをテストする方法を学びます。
どこで止めたの
最後のパートの最後で、ブログの「ライブ」コメントのクールなシステムを完成させました。 しかし、私の恐ろしいことに、テストのための十分な時間がありませんでした! 今日はそれらの世話をします。 以前の記事とは対照的に、この記事は明確で短くなります。
ゴミを拾います
テストに進む前に、いくつかの場所を厳しくする必要があります。 まず、電源を入れましょう
broadcast
コールのapproved
フラグ。 このようにして、確認コメントのステータスの変化をテストでチェックできるようになります。
new_payload = payload |> Map.merge(%{ insertedAt: comment.inserted_at, commentId: comment.id, approved: comment.approved }) broadcast socket, "APPROVED_COMMENT", new_payload
また、 web/channels/comment_helper.ex
ファイルを変更して、コメントの承認/削除のリクエストによってソケットに送信された空のデータに応答するようにする必要があります。 approve
機能の後にapprove
追加します。
def approve(_params, %{}), do: {:error, "User is not authorized"} def approve(_params, nil), do: {:error, "User is not authorized"}
delete
機能の後:
def delete(_params, %{}), do: {:error, "User is not authorized"} def delete(_params, nil), do: {:error, "User is not authorized"}
これにより、コードが簡単になり、エラー処理が改善され、テストが簡単になります。
コメントヘルパーのテスト
以前にExMachina
でExMachina
たファクトリを使用します。 コメントの作成をテストするとともに、ユーザーの承認に基づいてコメントを承認/拒否/削除する必要があります。 ファイルtest/channels/comment_helper_test.exs
作成し、準備コードを先頭に追加します。
defmodule Pxblog.CommentHelperTest do use Pxblog.ModelCase alias Pxblog.Comment alias Pxblog.CommentHelper import Pxblog.Factory setup do user = insert(:user) post = insert(:post, user: user) comment = insert(:comment, post: post, approved: false) fake_socket = %{assigns: %{user: user.id}} {:ok, user: user, post: post, comment: comment, socket: fake_socket} end # Insert our tests after this line end
ModelCase
モジュールを使用して、 setup
ブロックを使用する機能を追加しsetup
。 Comment
、 Factory
およびCommentHelper
モジュールのエイリアスを以下に追加して、それらの関数を簡単に呼び出せるようにします。
次に、各テストで使用できるいくつかの基本データのセットアップがあります。 前と同様に、ユーザー、投稿、コメントがここに作成されます。 ただし、キーassigns
のみを含む「偽のソケット」の作成に注意してください。 それをCommentHelper
渡すと、彼はそれを実際のソケットCommentHelper
ことができます。
次に、アトムからなるタプルが返され:ok
およびリスト辞書(および他のテスト)。 テストを自分で書きましょう!
コメントを作成するための最も簡単なテストから始めましょう。 どのユーザーもコメントを書くことができるため、ここでは特別なロジックは必要ありません。 コメントが実際に作成されたことを確認します...それだけです!
test "creates a comment for a post", %{post: post} do {:ok, comment} = CommentHelper.create(%{ "postId" => post.id, "author" => "Some Person", "body" => "Some Post" }, %{}) assert comment assert Repo.get(Comment, comment.id) end
これを行うには、 CommentHelper
モジュールからcreate
関数を呼び出し、この情報がチャネルから受信されたかのように情報を渡します。
コメントの承認に進みます。 ここではもう少し承認ロジックが使用されるため、テストはもう少し複雑になります。
test "approves a comment when an authorized user", %{post: post, comment: comment, socket: socket} do {:ok, comment} = CommentHelper.approve(%{"postId" => post.id, "commentId" => comment.id}, socket) assert comment.approved end test "does not approve a comment when not an authorized user", %{post: post, comment: comment} do {:error, message} = CommentHelper.approve(%{"postId" => post.id, "commentId" => comment.id}, %{}) assert message == "User is not authorized" end
コメントの作成と同様に、 CommentHelper.approve
関数を呼び出して、「チャネルから」情報を渡します。 関数に「偽のソケット」を渡すと、 assign
値にアクセスできます。 有効なソケット(ログインしているユーザー)と無効なソケット(空のassign
)でそれらの両方をテストします。 次に、肯定的な結果でコメントを受け取り、否定的な結果でエラーメッセージを受け取ることを確認します。
次に、取り外しテストについて説明します(基本的に同じです)。
test "deletes a comment when an authorized user", %{post: post, comment: comment, socket: socket} do {:ok, comment} = CommentHelper.delete(%{"postId" => post.id, "commentId" => comment.id}, socket) refute Repo.get(Comment, comment.id) end test "does not delete a comment when not an authorized user", %{post: post, comment: comment} do {:error, message} = CommentHelper.delete(%{"postId" => post.id, "commentId" => comment.id}, %{}) assert message == "User is not authorized" end
前述したように、テストはほぼ同じですが、肯定的な結果を除き、コメントが削除され、データベースに表示されなくなったことを確認します。
コードが適切にテストされていることを確認しましょう。 これを行うには、次のコマンドを実行します。
$ mix test test/channels/comment_helper_test.exs --cover
彼女は[project root]/cover
ディレクトリにレポートを作成し、テストでカバーされていないコードを教えてくれます。 すべてのテストが緑色の場合、ブラウザでファイルを開きます./cover/Elixir.Pxblog.CommentHelper.html
。 赤が表示されている場合、このコードはテストの対象外です。 赤い色がないことは、100%のカバレッジを意味します。
完全なコメントヘルパーテストファイルは次のとおりです。
defmodule Pxblog.CommentHelperTest do use Pxblog.ModelCase alias Pxblog.Comment alias Pxblog.CommentHelper import Pxblog.Factory setup do user = insert(:user) post = insert(:post, user: user) comment = insert(:comment, post: post, approved: false) fake_socket = %{assigns: %{user: user.id}} {:ok, user: user, post: post, comment: comment, socket: fake_socket} end # Insert our tests after this line test "creates a comment for a post", %{post: post} do {:ok, comment} = CommentHelper.create(%{ "postId" => post.id, "author" => "Some Person", "body" => "Some Post" }, %{}) assert comment assert Repo.get(Comment, comment.id) end test "approves a comment when an authorized user", %{post: post, comment: comment, socket: socket} do {:ok, comment} = CommentHelper.approve(%{"postId" => post.id, "commentId" => comment.id}, socket) assert comment.approved end test "does not approve a comment when not an authorized user", %{post: post, comment: comment} do {:error, message} = CommentHelper.approve(%{"postId" => post.id, "commentId" => comment.id}, %{}) assert message == "User is not authorized" end test "deletes a comment when an authorized user", %{post: post, comment: comment, socket: socket} do {:ok, comment} = CommentHelper.delete(%{"postId" => post.id, "commentId" => comment.id}, socket) refute Repo.get(Comment, comment.id) end test "does not delete a comment when not an authorized user", %{post: post, comment: comment} do {:error, message} = CommentHelper.delete(%{"postId" => post.id, "commentId" => comment.id}, %{}) assert message == "User is not authorized" end end
コメントチャンネルのテスト
ジェネレーターはすでにチャネルテストの基礎を作成しており、それらを肉で埋めることは残っています。 Pxblog.Factory
、 Pxblog.Factory
エイリアスを追加して、 setup
ブロックでファクトリーを使用しsetup
。 実際、すべては以前と同じです。 次に、ソケットを設定する必要があります。つまり、作成されたユーザーとして自分自身を紹介し、作成された投稿のコメントチャンネルに接続します。 ping
およびbroadcast
テストはそのままにしておきping
、このハンドラーがなくなったため、 shout
に関連するテストは削除します。 ファイルtest/channels/comment_channel_test.exs
:
defmodule Pxblog.CommentChannelTest do use Pxblog.ChannelCase alias Pxblog.CommentChannel alias Pxblog.Factory setup do user = Factory.create(:user) post = Factory.create(:post, user: user) comment = Factory.create(:comment, post: post, approved: false) {:ok, _, socket} = socket("user_id", %{user: user.id}) |> subscribe_and_join(CommentChannel, "comments:#{post.id}") {:ok, socket: socket, post: post, comment: comment} end test "ping replies with status ok", %{socket: socket} do ref = push socket, "ping", %{"hello" => "there"} assert_reply ref, :ok, %{"hello" => "there"} end test "broadcasts are pushed to the client", %{socket: socket} do broadcast_from! socket, "broadcast", %{"some" => "data"} assert_push "broadcast", %{"some" => "data"} end end
CommentHelper
モジュール用の本格的なテストをすでに作成しているので、ここではチャネルの機能に直接関連するテストを残します。 CREATED_COMMENT
、 APPROVED_COMMENT
、およびDELETED_COMMENT
3つのメッセージのテストを作成しましょう。
test "CREATED_COMMENT broadcasts to comments:*", %{socket: socket, post: post} do push socket, "CREATED_COMMENT", %{"body" => "Test Post", "author" => "Test Author", "postId" => post.id} expected = %{"body" => "Test Post", "author" => "Test Author"} assert_broadcast "CREATED_COMMENT", expected end
これまでにチャネルテストを見たことがない場合、ここではすべてが新しいように見えます。 手順を見ていきましょう。
まず、 setup
ブロックで作成したソケットとポストをテストに渡しsetup
。 次の行では、クライアントが実際にソケットに送信するものと同様の連想配列とともにCREATED_COMMENT
イベントをソケットに送信します。
次に、「期待」について説明します。 これまでのところ、 assert_broadcast
関数内で他の変数を参照するリストを定義することはできません 。そのため、期待値を個別に定義し、 expected
変数をassert_broadcast
呼び出しに渡す習慣を身に付ける必要があります。 ここでは、 body
とauthor
値が、内部で渡したものauthor
一致することを期待しています。
最後に、 CREATED_COMMENT
メッセージが予想される連想配列とともにブロードキャストされたことを確認します。
次に、 APPROVED_COMMENT
イベントに移動します。
test "APPROVED_COMMENT broadcasts to comments:*", %{socket: socket, post: post, comment: comment} do push socket, "APPROVED_COMMENT", %{"commentId" => comment.id, "postId" => post.id, approved: false} expected = %{"commentId" => comment.id, "postId" => post.id, approved: true} assert_broadcast "APPROVED_COMMENT", expected end
このテストは、 false
に等しいapproved
値をソケットに渡し、実行後にtrue
に等しいapproved
値が表示approved
れることを期待することを除いて、前のテストとほぼ同じです。 expected
変数では、 commentId
とpostId
をcommentId
とpostId
へのポインターとして使用していることに注意してください。 これらの式はエラーの原因となるため、 assert_broadcast
関数で期待される変数の分離を使用する必要があります。
最後に、 DELETED_COMMENT
メッセージのテストを見てください。
test "DELETED_COMMENT broadcasts to comments:*", %{socket: socket, post: post, comment: comment} do payload = %{"commentId" => comment.id, "postId" => post.id} push socket, "DELETED_COMMENT", payload assert_broadcast "DELETED_COMMENT", payload end
本当に面白いものはありません。 標準データをソケットに転送し、コメントの削除に関するイベントをブロードキャストしていることを確認します。
CommentHelper
で行ったように、このファイル専用のテストを--cover
オプションで--cover
ます:
$ mix test test/channels/comment_channel_test.exs --cover
expected
変数が使用されていないという警告が表示expected
ますが 、無視しても問題ありません 。
test/channels/comment_channel_test.exs:31: warning: variable expected is unused test/channels/comment_channel_test.exs:37: warning: variable expected is unused
./cover/Elixir.Pxblog.CommentChannel.html
ファイルを開いて、赤いものが何も表示されない場合、「Hurray!」と叫ぶことができます。 完全なカバレッジ!
CommentChannel
テストの最終バージョンは次のようになります。
defmodule Pxblog.CommentChannelTest do use Pxblog.ChannelCase alias Pxblog.CommentChannel import Pxblog.Factory setup do user = insert(:user) post = insert(:post, user: user) comment = insert(:comment, post: post, approved: false) {:ok, _, socket} = socket("user_id", %{user: user.id}) |> subscribe_and_join(CommentChannel, "comments:#{post.id}") {:ok, socket: socket, post: post, comment: comment} end test "ping replies with status ok", %{socket: socket} do ref = push socket, "ping", %{"hello" => "there"} assert_reply ref, :ok, %{"hello" => "there"} end test "broadcasts are pushed to the client", %{socket: socket} do broadcast_from! socket, "broadcast", %{"some" => "data"} assert_push "broadcast", %{"some" => "data"} end test "CREATED_COMMENT broadcasts to comments:*", %{socket: socket, post: post} do push socket, "CREATED_COMMENT", %{"body" => "Test Post", "author" => "Test Author", "postId" => post.id} expected = %{"body" => "Test Post", "author" => "Test Author"} assert_broadcast "CREATED_COMMENT", expected end test "APPROVED_COMMENT broadcasts to comments:*", %{socket: socket, post: post, comment: comment} do push socket, "APPROVED_COMMENT", %{"commentId" => comment.id, "postId" => post.id, approved: false} expected = %{"commentId" => comment.id, "postId" => post.id, approved: true} assert_broadcast "APPROVED_COMMENT", expected end test "DELETED_COMMENT broadcasts to comments:*", %{socket: socket, post: post, comment: comment} do payload = %{"commentId" => comment.id, "postId" => post.id} push socket, "DELETED_COMMENT", payload assert_broadcast "DELETED_COMMENT", payload end end
最後の仕上げ
テストカバレッジレポートはMixを使用して簡単に作成できるため、Git履歴に含めることは意味がないため、 .gitignore
ファイルを開いて次の行を追加します。
/cover
以上です! これで、テストで完全にカバーされたチャネルコードが得られました(Javascriptテストは例外で、これはこの一連のレッスンに適合しない別の世界です)。 次の部分では、プロジェクトをよりプロフェッショナルに見えるようにするために、UIでの作業に進み、UIを少しきれいで機能的にし、標準スタイル、ロゴなどを置き換えます。 さらに、私たちのサイトの使いやすさはまったくありません。 人々が私たちのブログプラットフォームを使いたいと思うように、これも修正します!