每次测试后停止 GenServer
Posted
技术标签:
【中文标题】每次测试后停止 GenServer【英文标题】:Stop a GenServer after each test 【发布时间】:2021-04-14 05:17:34 【问题描述】:背景
我有一组测试需要先启动 GenServer。根据经验,我知道在每次测试后进行清理是一个好习惯,所以我也想在。
问题
这里的问题是我不知道如何在测试完成后停止 GenServer。我总是遇到一些并发问题。
defmodule MyModuleTest do
use ExUnit.Case
alias MyModule
setup do
MyModule.Server.start_link(nil)
context_info = 1
more_info = 2
%context_info: context_info, more_info: more_info
end
describe "some tests" do
test "returns :ok, order_id if order was deleted correctly", context do
# do test here that uses created server and passed context
assert actual == expected
#clean up?
end
end
end
现在,我尝试了on_exit
/2,如下所示:
setup do
:ok, server = MyModule.Server.start_link(nil)
context_info = 1
more_info = 2
on_exit(fn -> GenServer.stop(server) end)
%context_info: context_info, more_info: more_info
end
但我得到这个错误:
** (exit) exited in: GenServer.stop(#PID<0.296.0>, :normal, :infinity)
** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
我觉得这退出得太早了。
我也尝试过使用start_supervised
,但是由于我的GenServer
在handle_continue
中的初始化时间很长,因此测试在服务器准备好之前运行。
问题
我该如何解决这个问题?
【问题讨论】:
【参考方案1】:我终于搞清楚是怎么回事了。
原来start_supervised
正在按预期工作,实际上是等待 GenServer 结束 handle_continue
(嗯,它不是完全等待,它仍然发送消息并将这些消息放入队列中等待适当的时间执行)。
这里的问题是我没有完全清理我在handle_continue
中发起的所有内容。原来我启动的一些连接和进程即使在原始 GenServer 死后仍然存在。
解决方案有两个方面:
捕捉所有停止信号 一旦检测到停止信号,执行正常关机在代码中,这被翻译成:
def init(_) do
Process.flag(:trap_exit, true) # trap all exits!
:ok, %, :continue, :setup_queue
end
def handle_continue(:setup_queue, state) do
# do heavy lifting
:noreply, state
end
def terminate(_reason, state), do:
# undo heavy lifting
有了这个和start_supervised
在我的setup
块中,一切正常。
【讨论】:
有趣!哪些连接和进程在 GenServer 死亡后幸存下来? 就我而言,我使用的是一个名为 :jobs, github.com/uwiger/jobs 的库。创建队列的进程死亡后,创建的队列不会被删除。所以我不得不手动完成。以上是关于每次测试后停止 GenServer的主要内容,如果未能解决你的问题,请参考以下文章
如何在一段时间后或每次我对文件进行更改时停止 npm start?