Testing async tasks

Hi @mustela!

I agree with @LostKobrakai’s response from the topic you linked: Testing Task Async - #2 by LostKobrakai. I would refactor the code to unit test only the abstractions that I have control over and by definition can properly be observed.

I’d say that if both functions inside onboard/1 don’t depend on each other, you should probably be unit-testing them separately. On the other hand, if they do and you’re not using await to guarantee the task has run, you’ll probably have to deal with some sort of race condition.

So the question in my head is if you should be using async at this level of the abstraction. Perhaps you should make the code inside process_onboard/1 async, but the process_onboard/1 function itself returns something like {:ok | :error}.

For example, this would be easier to test:

def process_onboard(email) do
  task1 = do_some_stuff()
  task2 = do_some_more_stuff()
  task3 = do_even_more_stuff()

 Task.await_many([task1, task2, task3])

  :ok
end

def do_some_stuff(), do: :ok
def do_some_more_stuff(), do: :ok
def do_even_more_stuff(), do: :ok
defmodule Personas
  def onboard(email) do
    with :ok <- process_onboard(email), do: init_state()
  end
end

I’m quoting this because when we are talking about code that it’s difficult to test we can most of the time correlate with abstraction problems.

Update: I want to link this Kent Beck post because I feel this is relevant to the discussion. Hope that this helps you find out which abstractions of your application should be tested.

3 Likes