Created
June 8, 2024 08:16
-
-
Save amos-kibet/12d1788a3d172102b18722a651834804 to your computer and use it in GitHub Desktop.
Testing async Elixir code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## Method 1 (from Dockyard's [blog post](https://dockyard.com/blog/2024/06/06/a-better-solution-for-waiting-for-async-tasks-in-tests)) | |
Create a helper module, with this function: | |
```Elixir | |
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, call the function, after your code execution, but before your assertions. | |
```Elixir | |
test "does something async" do | |
MyApp.do_something_async() | |
flush_task_supervisor() | |
assert MyApp.check_something() | |
end | |
``` | |
## Method 2 (the one I ue all the time) | |
First, start a Task supervisor in all environments (dev, stage, etc), except in test environment. Only start the supervisor in the specific tests that need it. | |
```Elixir | |
# *my_app/lib/my_app/application.ex* | |
def start(type, args) do | |
children = [_other_children] ++ more_children() | |
end | |
defp more_children(env \\ Application.get_env(:my_app, :env)) | |
defp more_children(:test), do: [] | |
defp more_children(_env), do: [{Task.Supervisor, name: MyApp.TaskSupervisor}] | |
``` | |
Then, in your specific tests that has async code, add this to your test setup: | |
```Elixir | |
setup do | |
start_supervised!({Task.Supervisor, name: MyApp.TaskSupervisor, strategy: :one_for_one}) | |
:ok | |
end | |
``` | |
and write your tests normally. The setup will ensure that before your test exits, the async Task process will have returned. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Method 1 (from Dockyard's blog post)
Create a helper module, with this function:
Then, in your test, call the function, after your code execution, but before your assertions.
Method 2 (the one I ue all the time)
First, start a Task supervisor in all environments (dev, stage, etc), except in test environment. Only start the supervisor in the specific tests that need it.
Then, in your specific tests that has async code, add this to your test setup:
and write your tests normally. The setup will ensure that before your test exits, the async Task process will have returned.