我正在构建一个以特定顺序发送消息的Elixir模块.我写了这样的单元测试
MyModule.send_msgs(self())
assert_received {:event, 1}
assert_received {:event, 2}
assert_received {:event, 3}
Run Code Online (Sandbox Code Playgroud)
问题是,即使我改变assert_received顺序,测试仍然通过.
MyModule.send_msgs(self())
assert_received {:event, 2}
assert_received {:event, 1}
assert_received {:event, 3}
Run Code Online (Sandbox Code Playgroud)
似乎assert_received并不关心消息到达的顺序.不仅如此assert_received,据我记忆,receive也可能无法收到消息.所以,我的问题是,如果无法收到消息,您如何确保到达消息的顺序?
似乎没有现成的功能来执行此操作,但是很容易创建自己的宏,该宏声明邮箱中的下一条消息与特定模式匹配:
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
Run Code Online (Sandbox Code Playgroud)
测试:
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
Run Code Online (Sandbox Code Playgroud)
输出:
.
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
Run Code Online (Sandbox Code Playgroud)