我已经搜索了相当多的东西,我无法找到关于这个主题的任何内容 - 无论是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
但是当我运行测试时,我一直收到这个错误:
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
所以,我想知道是否有更好的方法可以做到这一点,或者我的代码很糟糕。
答案 0 :(得分:3)
Process.exit/1
发送退出信号,但不等待进程停止。根据您的错误输出判断,Portal.Door.get/1
似乎失败,因为gen_server进程在收到调用消息之前终止。
要解决此问题,您需要等待进程关闭,然后重新启动。发出退出信号后,一个简单的补救措施可能是通过:timer.sleep/1
进行短暂的睡眠(比如说100毫秒)。
更复杂的方法是等待进程终止,然后再次重新启动。第一部分可以通过设置监视器(通过Process.monitor/1
)轻松完成,并等待相应的:DOWN
消息。通过这样做,您还可以验证目标进程是否确实已终止。
然后您需要等待重新启动进程,以便发出请求。这可能很棘手,短时间睡觉可能是最简单的选择。或者,如果进程是在本地别名下注册的,则可以使用Process.whereis/1
进行轮询,直到获得非零值,此时您就知道该进程再次运行。