Whether you need end-to-end product development support or the engineering know-how for a targeted project, we can help. Book a free consult to learn more.
When you’re writing tests for code that involves async tasks, sometimes you need to make sure that your tests wait for the async tasks to complete before continuing with the test or making assertions. Or you might just be tired of seeing a bunch of Ecto sandbox error logs when your test process terminates and your async tasks were using the database.
The quick and dirty solution is to throw in some sort of sleep
function to wait for a certain
number of milliseconds before continuing with the test. However, this is imprecise and requires you to
draw a balance between fragility and slowness.
A better solution is to use assert_receive
and here is a test helper for Supervised Tasks that can help with that:
def flush_task_supervisor do
pids = Task.Supervisor.children(MyApp.TaskSupervisor)
for pid <- pids do
ref = Process.monitor(pid)
assert_receive {:DOWN, ^ref, _, _, _}
end
end
Then in your test, you can call flush_task_supervisor/0
to wait for the tasks to complete:
test "does something async" do
MyApp.do_something_async()
flush_task_supervisor()
assert MyApp.check_something()
end
I got this tip (or something like it) several years ago, and I’m pretty sure it was José Valim who suggested it, so shout out to him for always being helpful to the Elixir community.
I end up using this in almost every project that has tasks, and maybe you should too!