Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elixir 测试使用GenServer.cast的代码_Elixir - Fatal编程技术网

Elixir 测试使用GenServer.cast的代码

Elixir 测试使用GenServer.cast的代码,elixir,Elixir,我有一个测试,模拟了应用程序范围内的回购。大多数时候,测试都是绿色的。当我使用相同的种子在循环中运行测试时,可能有10%的运行成功,但有一条GenServer终止消息: 15:39:34.632 [error] GenServer ShortTermMessageStore terminating ** (CaseClauseError) no case clause matching: {:error, %Postgrex.Error{connection_id: 11136, message

我有一个测试,模拟了应用程序范围内的回购。大多数时候,测试都是绿色的。当我使用相同的种子在循环中运行测试时,可能有10%的运行成功,但有一条GenServer终止消息:

15:39:34.632 [error] GenServer ShortTermMessageStore terminating
** (CaseClauseError) no case clause matching: {:error, %Postgrex.Error{connection_id: 11136, message: nil, postgres: %{code: :foreign_key_violation, constraint: "chat_messages_room_id_ref_fkey", detail: "Key (room_id_ref)=(c78940ab-2514-493e-81fe-64efc63c7bb0) is not present in table \"chat_rooms\".", file: "ri_triggers.c", line: "3324", message: "insert or update on table \"chat_messages\" violates foreign key constraint \"chat_messages_room_id_ref_fkey\"", pg_code: "23503", routine: "ri_ReportViolation", schema: "public", severity: "ERROR", table: "chat_messages", unknown: "ERROR"}}}
    (chat_web) lib/chat_web/repo.ex:78: ChatWeb.Repo.append_message_to_store/3
    (chat_web) lib/short_term_message_store.ex:23: ChatWeb.ShortTermMessageStore.handle_cast/2
    (stdlib) gen_server.erl:601: :gen_server.try_dispatch/4
    (stdlib) gen_server.erl:667: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: {:"$gen_cast", {:published, "USERID", "c78940ab-2514-493e-81fe-64efc63c7bb0", %{"id" => "123", "room_id" => "c78940ab-2514-493e-81fe-64efc63c7bb0"}}}
我相信我把问题归结到了一次测试。当我注释掉该测试时,我可以一次运行测试几分钟而看不到任何警告

有关守则是:

test_with_mock "publish_message appends message to room", Repo, [], [append_message_to_store: fn(_, _, _) -> true end] do
  room_id = "c78940ab-2514-493e-81fe-64efc63c7bb0"
  {:ok, _room} = open_room room_id
  sock = open_socket()
        |> subscribe_and_join!(RoomChannel, "room:#{room_id}")

  push sock, "publish_message", %{"id" => "123", "room_id" => room_id}

  assert_broadcast "publish_message", %{"id" => "123", "room_id" => room_id, "sequence" => 1}
  {:ok, mailbox} = Rooms.mailbox(room_id)
  assert [%{"id" => "123", "room_id" => "c78940ab-2514-493e-81fe-64efc63c7bb0", "sequence" => 1}] = mailbox
end

defmodule RoomChannel do
  def handle_in("publish_message", payload, socket) do
    {:ok, message} = Rooms.publish(payload["room_id"], payload)
    broadcast(socket, "publish_message", message)

    ShortTermMessageStore.publish(socket.assigns[:user_id], payload["room_id"], payload)

    {:reply, {:ok, %{payload: payload}}, socket}
  end
end

defmodule ShortTermMessageStore do
  def publish(user_id, room_id, message) do
    GenServer.cast(ShortTermMessageStore.address, {:published, user_id, room_id, message})
  end

  def handle_cast({:published, user_id, room_id, message}, state) do
    Logger.debug fn -> "STMS: #{inspect(message)}" end
    Repo.append_message_to_store(user_id, room_id, message)
    {:noreply, state}
  end
end
代码流是:
RoomChannel
handle\u in({:publish\u message})
被调用。这将调用业务逻辑,然后调用
ShortTermMessageStore
。这将执行
GenServer.cast
,然后返回。测试运行从中断的地方开始,测试和模拟被删除。我相信在某些情况下,测试和模拟很快就被拆掉了:
cast
还没有开始,Repo的真正实现已经运行。这将生成我在上面粘贴的消息,在这里我们尝试运行SQL
INSERT
语句,但它失败了,因为尚未为外键设置DB

我知道,根据设计,强制转换不应该支持回复。为了我的测试,我能提供什么帮助?我回来之前需要睡觉吗?这看起来既粗俗又不雅观

我已经找到了哪些元素是好的,但是在我的例子中,我没有测试异步对象。这只是调用另一个函数的副作用


我还发现了这一点,这让我觉得我可能需要监视一些东西。

思考了这一点后,我还嘲笑了ShortTermMessageStore:

test "publish_message appends message to room" do
  with_mocks([
    {ShortTermMessageStore, [], [publish: fn(_, _, _) -> true end]},
    {Repo, [], [is_authorized_to_join: fn(_, _) -> true end, is_authorized_to_publish_message_to_room: fn(_, _) -> true end, append_message_to_store: fn(_, _, _) -> true end]},
  ]) do
    {:ok, _room} = open_room "c78940ab-2514-493e-81fe-64efc63c7bb0"
    sock = open_socket()
          |> subscribe_and_join!(RoomChannel, "room: c78940ab-2514-493e-81fe-64efc63c7bb0")

    push sock, "publish_message", %{"id" => "123", "room_id" => "c78940ab-2514-493e-81fe-64efc63c7bb0"}

    assert_broadcast "publish_message", %{"id" => "123", "room_id" => "c78940ab-2514-493e-81fe-64efc63c7bb0", "sequence" => 1}
    {:ok, mailbox} = Rooms.mailbox("c78940ab-2514-493e-81fe-64efc63c7bb0")
    assert [%{"id" => "123", "room_id" => "c78940ab-2514-493e-81fe-64efc63c7bb0", "sequence" => 1}] = mailbox
  end
end

使用这个模拟,我能够连续运行测试很多分钟,没有失败或警告消息。

您可以通过调用Pid上的
:sys.get_state/1
等待GenServer处理完所有挂起的消息<代码>:sys.get_state/1对GenServer进行同步调用以获取其状态,该操作将在GenServer处理完所有挂起的消息后完成

因此,如果在测试结束时添加以下代码,测试将等待
ShortTermMessageStore.address
处理它已经收到的所有消息

:sys.get_state(ShortTermMessageStore.address)

您是否确认,如果添加长睡眠(例如5秒),测试总是通过?睡眠100毫秒允许我的测试通过,因此,是的,我非常确定此测试是问题所在,并且测试被删除的顺序会影响日志。您是否可以尝试这样做而不是睡眠:
:sys.get\u state(ShortTermMessageStore.address)
。应该等到发送到
ShortTermMessageStore.address
的所有消息都处理完毕后再返回状态。在循环中运行测试时,请告诉我它是否有效。@Dogbert,已更新。测试没有生成简单的消息,而是实际失败。“module ShortTermMessageStore不可用”这真是奇怪
ShortTermMessageStore
模块的实际完整名称是否正确?