在Elixir中测试主管的最佳实践

use*_*226 5 elixir

我用Google搜索了一下,无法找到关于这个问题的任何内容 - 无论是Elixir还是一个语言太年轻还是我用错误的术语搜索.

我正在研究Jose Valim的Elixir Portal教程(https://howistart.org/posts/elixir/1),并正在构建练习测试(我已经构建了所有功能).

本教程的一部分是构建一个Supervisor,使Portal.Door模块具有容错能力.

我正在尝试使用以下代码测试容错(例如,如果不正确关闭,Supervisor将重新启动Portal.Door实例)

defmodule PortalTest do
  use ExUnit.Case, async: true

  ...

  test "supervisor restarts doors" do 
    {:ok, pid} = Portal.shoot(:third)
    Process.unlink(pid)
    Process.exit(pid, :shutdown)
    assert Portal.Door.get(:third) == [] #new doors initialize with an empty array
  end

end
Run Code Online (Sandbox Code Playgroud)

但是当我运行测试时,我不断收到此错误:

  1) test supervisor restarts doors (PortalTest)
     test/portal_test.exs:35
     ** (exit) exited in: GenServer.call(:third, {:get, #Function<3.47016826/1 in Portal.Door.get/1>}, 5000)
         ** (EXIT) shutdown
     stacktrace:
       (elixir) lib/gen_server.ex:356: GenServer.call/3
       test/portal_test.exs:39
Run Code Online (Sandbox Code Playgroud)

所以,我想知道是否有更好的方法来做到这一点,或者我的代码是坏的.

sas*_*ric 5

Process.exit/1发送退出信号但不等待进程停止。根据您的错误输出判断,它看起来像Portal.Door.get/1then 失败,因为 gen_server 进程在收到调用消息之前终止。

为了克服这个问题,您需要等待进程关闭,然后再次重新启动。一个简单的补救措施可能是:timer.sleep/1在您发出退出信号后进行短暂的睡眠(例如 100 毫秒)。

更复杂的方法是等待进程终止,然后再次重新启动。通过设置监视器(通过Process.monitor/1)并等待相应的:DOWN消息,可以轻松完成第一部分。通过这样做,您还可以验证目标进程确实已终止。

然后需要等待进程再次重启,才能发出请求。这可能很棘手,短暂的睡眠可能是最简单的选择。或者,如果进程是在本地别名下注册的,您可以轮询Process.whereis/1直到获得非 nil 值,此时您知道该进程再次运行。