微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

每次测试后停止 GenServer

如何解决每次测试后停止 GenServer

背景

我有一组测试需要之前启动 GenServer。根据经验,我知道每次测试后进行清理是一个很好的做法,所以我也想在每次测试后停止 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,但是因为我的 GenServerhandle_continue 中有一个冗长的初始化,测试在服务器准备好之前运行。

问题

我该如何解决这个问题?

解决方法

我终于弄清楚发生了什么。

结果 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,一切都很好。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。