通过handle_info对周期性定时器进行单元测试

时间:2018-06-18 17:46:36

标签: unit-testing async-await elixir gen-server

我有一个GenServer执行定期操作,如下所示:

defmodule Hello
  use GenServer
  def init(_) do
    Process.send_after(self(), :timer, 1000)
    {:ok, %{}}
  end

  def handle_info(:timer, state) do
    # do stuff
    Process.send_after(self(), :timer, 1000)
    {:noreply, state}
  end
end

我试图找出对其进行单元测试的最佳方法。我最初的想法是使用mox来存根Process.send_after。这工作正常,但在我的单元测试中,我尝试过这样的事情:

test "the timer callback does the right thing" do
  MyMock |> expect(:timer, fn -> :ok end)
  {:ok, pid} = start_supervised(Hello, [])
  Process.send(pid, :timer)
  # assert the right thing happens
end

但是,这不起作用,因为Process.send是异步的,并且不会给我任何回报。我还能如何测试handle_info回调?

1 个答案:

答案 0 :(得分:0)

有许多选项,例如可能会从setup_all回调中生成Agent并在模拟和断言中使用它:

expect(MyMock, :timer, fn -> Agent.update(MyAgent, & &1 + 1))
...
Process.sleep(1_100)                 # ensure all sent
assert Agent.get(MyAgent, & &1) == 1 # number of calls

最简单的方法是捕获IO:

import ExUnit.CaptureLog
...
test "the timer callback does the right thing" do
  MyMock |> expect(:timer, fn -> IO.inspect(:ok) end)
  {:ok, pid} = start_supervised(Hello, [])

  assert capture_log(fn ->
    Process.send(pid, :timer)
    Process.sleep(1_100)
  end) =~ "ok" 
end