如何断言Elixir消息按顺序到达

时间:2017-01-09 08:04:44

标签: elixir

我正在构建一个以特定顺序发送消息的Elixir模块。我写了像这样的单元测试

MyModule.send_msgs(self())
assert_received {:event, 1}
assert_received {:event, 2}
assert_received {:event, 3}

问题是,即使我改变了assert_received命令,测试仍然通过。

MyModule.send_msgs(self())
assert_received {:event, 2}
assert_received {:event, 1}
assert_received {:event, 3}

似乎assert_received并不关心邮件到达的顺序。不仅仅是assert_received,据我所知,receive也可能无法收到消息。 所以,我的问题是,如果收到的消息可以无序接收,你如何确保到达消息的顺序?

1 个答案:

答案 0 :(得分:7)

这似乎不是一个现有的功能,但是很容易制作自己的宏,它断言邮箱中的下一条消息与特定模式匹配:

defmacro assert_next_receive(pattern, timeout \\ 100) do
  quote do
    receive do
      message ->
        assert unquote(pattern) = message
    after unquote(timeout) ->
      raise "timeout" # you might want to raise a better message here
    end
  end
end

测试:

defmodule MTest do
  use ExUnit.Case

  def send_msgs(pid) do
    send pid, {:event, 1}
    send pid, {:event, 2}
    send pid, {:event, 3}
  end

  defmacro assert_next_receive(pattern, timeout \\ 100) do
    quote do
      receive do
        message ->
          assert unquote(pattern) = message
      after unquote(timeout) ->
        raise "timeout" # you might want to raise a better message here
      end
    end
  end

  test "should pass" do
    send_msgs(self())
    assert_next_receive {:event, 1}
    assert_next_receive {:event, 2}
    assert_next_receive {:event, 3}
  end

  test "should fail" do
    send_msgs(self())
    assert_next_receive {:event, 1}
    assert_next_receive {:event, 3}
    assert_next_receive {:event, 2}
  end
end

输出:

.

  1) test should fail (MTest)
     test/m_test.exs:29
     match (=) failed
     code:  {:event, 3} = message
     right: {:event, 2}
     stacktrace:
       test/m_test.exs:32: (test)



Finished in 0.05 seconds
2 tests, 1 failure

Randomized with seed 351622