测试时Ecto 2.0 SQL沙箱错误

jef*_*on3 8 elixir ecto phoenix-framework

我最近将我的凤凰项目升级到了Ecto 2.0.2.我有一些代码用于Task.Supervisor.async_nolink在自己的线程上对db进行一些更新.我的测试运行时出现以下错误(仅在我的测试中发生)

[error] Postgrex.Protocol (#PID<0.XXX.0>) disconnected: **
(DBConnection.ConnectionError) owner #PID<0.XXX.0> exited while 
client #PID<0.XXX.0> is still running with: shutdown
Run Code Online (Sandbox Code Playgroud)

现在我我了解发生了什么:在db事务完成之前,正在检查Ecto Sandbox连接池.根据文档(至少我读它们的方式),解决这些问题的方法是使用共享连接池:Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, {:shared, self()})我正在做的事情.不幸的是,这不起作用.

如何设置我的测试以便不会发生此错误?

jef*_*on3 6

如果有其他人遇到这个,我直接从语言作者Jose Valim那里得到了答案:

是的,您对该问题的理解是正确的.这种情况正在发生,因为测试过程(拥有连接的人)已退出,但Task仍在使用其连接.使用{:shared,self()}无法修复它,因为测试仍然拥有连接,您只是隐式地共享它.

解决方法是在测试退出之前保证任务已完成.这可以通过调用Process.exit(task_pid,:kill)来完成.如果您不知道任务PID,您可以调用Task.Supervisor.which_children(NameOfYourTaskSupervisor)来返回您随后遍历并终止它们的所有PID.但是,如果执行此方法,则测试无法同时运行(因为您可能会杀死另一个测试启动的任务).


Mac*_*ski 5

我今天遇到了同样的问题,我想我找到了一个可能的解决方案,允许测试同时运行.

我正在使用此处描述的技术:http://blog.plataformatec.com.br/2015/10/mocks-and-explicit-contracts/在运行测试时替换Task.Supervisor.

代替:

Task.Supervisor.async_nolink(TaskSupervisor, fn -> (...) end)
Run Code Online (Sandbox Code Playgroud)

我正在做:

@task_supervisor Application.get_env(:app, :task_supervisor) || Task.Supervisor
# ...
@task_supervisor.async_nolink(TaskSupervisor, fn -> (...) end)
Run Code Online (Sandbox Code Playgroud)

然后我定义 TestTaskSupervisor

defmodule TestTaskSupervisor do
  def async_nolink(_, fun), do: fun.()
end
Run Code Online (Sandbox Code Playgroud)

并加config :app, :task_supervisor, TestTaskSupervisorconfig/test.exs.

这样,我确信任务将同步运行并在测试过程之前完成.