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"} 

これにより、コードが簡単になり、エラー処理が改善され、テストが簡単になります。


コメントヘルパーのテスト


以前にExMachinaExMachinaたファクトリを使用します。 コメントの作成をテストするとともに、ユーザーの承認に基づいてコメントを承認/拒否/削除する必要があります。 ファイル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ブロックを使用する機能を追加しsetupCommentFactoryおよび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.FactoryPxblog.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_COMMENTAPPROVED_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呼び出しに渡す習慣を身に付ける必要があります。 ここでは、 bodyauthor値が、内部で渡したもの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変数では、 commentIdpostIdcommentIdpostIdへのポインターとして使用していることに注意してください。 これらの式はエラーの原因となるため、 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. おわりに


Source: https://habr.com/ru/post/J333020/


All Articles