Elixir 防止;GenServer termining";有监督过程的exunit检验中的误差

Elixir 防止;GenServer termining";有监督过程的exunit检验中的误差,elixir,gen-server,ex-unit,Elixir,Gen Server,Ex Unit,我的Phoenix应用程序中有一个测试,它正在测试使用Genserver的订户。订阅者在其句柄\u info/2中执行一些数据库工作 test "sending creating a referral code upon user registration" do start_supervised(MyApp.Accounts.Subscriber) user = insert(:user) Phoenix.PubSub.broadcast(MappApp.Pu

我的Phoenix应用程序中有一个测试,它正在测试使用Genserver的订户。订阅者在其
句柄\u 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正在终止
**(停止)退出:DBConnection.Holder.checkout(#PID,[日志:#函数,缓存#语句:“外部插入#引用#代码”,超时:15000,池大小:10,池:DBConnection.Ownership])
**(退出)关机:“所有者#PID退出”
这似乎是一个问题,当进程终止时,数据库连接仍处于打开状态,因此不会正常关闭。但我不知道该怎么处理


关于如何防止这个错误有什么建议吗?

我今天遇到了这个问题。任何时候在单独的子进程中执行数据库操作(例如,在
GenStage
GenServer
等内部触发的数据库操作),都需要仔细阅读。有一个专门处理此错误的常见问题解答,解决方案可以是明确授予沙盒适配器对子进程的访问权限,如下所示(从文档中):

或者,您可以通过更改测试
设置来启用“共享”模式,以设置
沙盒
模式:

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

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

您是否有机会使用
async:true
运行此测试模块?如果是这样的话,那可能就是罪魁祸首。我正在
使用
ModelCase
模块。这是默认行为吗?如果您只有
use-ModelCase
(而不是
use-ModelCase,async:true
),那么模块中的测试将不会与其他模块中的测试同时运行,这可能是您想要的。(虽然我不知道您的ModelCase是什么样子)它基本上是库存的(现在在当前的Phoenix:中称为
DataCase
)。我尝试了使用和不使用
async:false
,出现了相同的错误。我认为
ModelCase
以非异步方式运行测试,这很奇怪,因为您给出的后一种解决方案实际上是我的
ModelCase
的默认行为,它似乎无法解决我遇到的错误。我还发现,即使省略了
start\u
,我的测试仍然通过,这意味着订阅进程正在运行。这怎么可能?您是否正在运行测试
async:false
?我已经尝试过使用和不使用。它也有同样的结果我不太明白的是,在测试运行中,
Subscriber
Genserver似乎是如何启动的,即使我删除了
start\u
调用。这怎么可能?这是一个非常标准的Phoenix应用程序,因此它启动的唯一其他位置是在应用程序文件中,我在
children
上调用
Supervisor.start\u link
,似乎Genserver是由测试运行者启动的,因为它位于Application.ex的
children
列表中。我不确定该怎么处理这个问题
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 do
    :ok = Sandbox.checkout(Repo)
    Sandbox.mode(Repo, {:shared, self()})
  end