Testing asynchronous code in Elixir

后端 未结 2 1153
不知归路
不知归路 2021-02-01 05:38

I want to test a function which is using Task.async

In order to make my test pass, I need to make it sleep for 100ms before assertions, otherwise the test p

相关标签:
2条回答
  • 2021-02-01 05:50

    When I cannot use José's approach involving assert_receive, I use a small helper to repeatedly do assertion / sleep, until the assertion pass or finally times out.

    Here is the helper module

    defmodule TimeHelper do
    
      def wait_until(fun), do: wait_until(500, fun)
    
      def wait_until(0, fun), do: fun.()
    
      def wait_until(timeout, fun) defo
        try do
          fun.()
        rescue
          ExUnit.AssertionError ->
            :timer.sleep(10)
            wait_until(max(0, timeout - 10), fun)
        end
      end
    
    end
    

    It can be used like this in former example:

    TSearch.search([q: "my query"])
    wait_until fn ->
      assert called TStore.store("some tweet from my fixtures")
      assert called TStore.store("another one")
    end
    
    0 讨论(0)
  • 2021-02-01 06:08

    Since the question is a bit vague, I will give the general answer here. The usual technique is to monitor the process and wait for the down message. Something like this:

    task = Task.async(fn -> "foo" end)
    ref  = Process.monitor(task.pid)
    assert_receive {:DOWN, ^ref, :process, _, :normal}, 500
    

    Some important things:

    • The fifth element of the tuple is the exit reason. I am asserting the Task exit is :normal. Change that accordingly if you are expecting another exit.

    • The second value in assert_receive is the timeout. 500 miliseconds sounds like a reasonable amount given you currently have a 100 ms sleep.

    0 讨论(0)
提交回复
热议问题