PhoenixとElixirでブログエンジンを作成する/パート10.チャネルテスト







翻訳者から: 「エリクサーとフェニックスは、最新の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を少しきれいで機能的にし、標準スタイル、ロゴなどを置き換えます。 さらに、私たちのサイトの使いやすさはまったくありません。 人々が私たちのブログプラットフォームを使いたいと思うように、これも修正します!







シリーズの他の記事



  1. エントリー
  2. ログイン
  3. 役割を追加
  4. コントローラーで役割を処理します
  5. ExMachinaを接続します
  6. マークダウンのサポート
  7. コメントを追加
  8. コメントで終了
  9. チャンネル
  10. チャネルテスト
  11. おわりに



All Articles