I am building an Elixir module that sends message in certain order. And I wrote unit tests like this
MyModule.send_msgs(self())
assert_received {:event, 1}
assert_received {:event, 2}
assert_received {:event, 3}
The problem is, even if I shuffle the assert_received
order, the test still passes.
MyModule.send_msgs(self())
assert_received {:event, 2}
assert_received {:event, 1}
assert_received {:event, 3}
It seems assert_received
doesn't care about the order of message arrival. Not just assert_received
, as far as I recall, receive
can also get messages out of order.
So, my question here is, how can you ensure the order of arriving message if they can be received out of order?
There doesn't seem to be an existing function to do this, but it's easy to make your own macro which asserts that the next message in the mailbox matches a specific pattern:
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:
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
Output:
.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With