【问题标题】:Prevent "GenServer terminating" error in exunit test with supervised process使用受监督的过程防止 exunit 测试中的“GenServer terminating”错误
【发布时间】:2021-03-08 07:14:19
【问题描述】:

我在我的 Phoenix 应用程序中有一个测试,它正在测试使用 Genserver 的 Phoenix.PubSub 订阅者。订阅者将一些数据库工作作为其handle_info/2 的一部分。

test "sending creating a referral code upon user registration" do
  start_supervised(MyApp.Accounts.Subscriber)
  user = insert(:user)

  Phoenix.PubSub.broadcast(MappApp.PubSub, "accounts", {:register, user})

  assert_eventually(Repo.exists?(ReferralCode))

  stop_supervised(MyApp.Accounts.Subscriber)
end

单独运行这个测试模块就可以了。但是,当我运行我的整个测试套件时,我会收到这样的错误(测试仍然通过):

[error] GenServer MyApp.Accounts.Subscriber terminating
** (stop) exited in: DBConnection.Holder.checkout(#PID<0.970.0>, [log: #Function<9.124843621/1 in Ecto.Adapters.SQL.with_log/3>, cache_statement: "ecto_insert_referral_codes", timeout: 15000, pool_size: 10, pool: DBConnection.Ownership])
    ** (EXIT) shutdown: "owner #PID<0.969.0> exited"
    <stacktrace...>

这看起来是一个问题,当进程终止时数据库连接仍处于打开状态,因此它不会优雅地终止。但我不确定如何处理。

关于如何防止此错误的任何建议?

【问题讨论】:

  • 你有没有机会用async: true 运行这个测试模块?如果是这样,那可能是罪魁祸首。
  • 我是useing ModelCase 模块。这是默认行为吗?
  • 如果您只有use ModelCase(而不是use ModelCase, async: true),那么模块中的测试将不会与其他模块中的测试同时运行,这可能是您想要的。 (虽然我不知道你的 ModelCase 长什么样)
  • 基本上是库存(现在在凤凰城称为DataCasegithub.com/phoenixframework/phoenix/blob/master/installer/…)。
  • 我尝试了使用和不使用async: false,并且发生了同样的错误。我认为ModelCase 运行测试非异步

标签: elixir gen-server ex-unit


【解决方案1】:

我今天遇到了这个。任何时候您在单独的子进程中执行数据库操作(例如,在GenStageGenServer 等中触发的数据库操作),那么您需要仔细阅读Sandbox adapter documentation。有一个专门处理此错误的常见问题解答,解决方案可以是显式授予沙盒适配器访问子进程的权限,如下所示(来自文档):

test "gets results from GenServer" do
  {:ok, pid} = MyAppServer.start_link()
  Ecto.Adapters.SQL.Sandbox.allow(Repo, self(), pid)
  assert MyAppServer.get_my_data_fast(timeout: 1000) == [...]
end

或者您可以通过更改您的测试setup 来设置Sandbox 模式来启用“共享”模式:

  setup do
    :ok = Sandbox.checkout(Repo)
    Sandbox.mode(Repo, {:shared, self()})
  end

我对后者的运气更好,但请注意,如果您在任何地方明确使用其他适配器(例如进行原始数据库调用),那么它可能会导致测试失败(因为它无法再获得连接) .

【讨论】:

  • 嗯,这很奇怪,因为您提供的后一种解决方案实际上是我的ModelCase 的默认行为,它似乎并没有解决我遇到的错误。我还发现即使省略了start_supervised,我的测试仍然通过,这意味着订阅者进程正在以某种方式运行。这怎么可能?
  • 你在运行测试async: false 吗?
  • 我试过有无。结果是一样的
  • 我不太明白的是Subscriber Genserver 在测试运行中是如何启动的,即使我删除了start_supervised 调用。这怎么可能?这是一个非常标准的 Phoenix 应用程序,因此它启动的唯一其他位置是在应用程序文件中,我在 children 上调用 Supervisor.start_link
  • 看起来 Genserver 是由测试运行程序启动的,因为它位于 application.ex 的 children 列表中。我不确定或处理这个问题的正确方法
猜你喜欢
  • 2017-01-09
  • 2018-03-28
  • 2016-09-20
  • 1970-01-01
  • 2014-09-13
  • 2015-06-12
  • 1970-01-01
  • 2015-09-27
  • 2015-05-02
相关资源
最近更新 更多