我在Elixir Phoenix项目中使用Ecto 2.0和MySQL。
根据Ecto2.0 documentation, MySQL不支持并发测试所以我想我应该使用use ExUnit.Case
而不是使用ExUnit.Case, async: true
,这样测试就不会同时运行。
在我的特定情况下,在我的测试中,我通过夹具在数据库中插入模型,并且一旦完成测试,由夹具插入的模型仍然保留在数据库中(由测试代码本身插入的模型得到清理)。我想删除夹具插入的模型。如果我这样做:
如果我这样做:
ExUnit.Case
setup do
on_exit fn ->
Repo.delete_all(ModelA)
Repo.delete_all(ModelB)
end
end
我明白了:
** (exit) exited in: GenServer.call(#PID<0.277.0>, {:checkout, #Reference<0.0.1.1885>, true, 15000}, 5000)
** (EXIT) shutdown: "owner #PID<0.276.0> exited with: shutdown"
stacktrace:
(db_connection) lib/db_connection/ownership/proxy.ex:32: DBConnection.Ownership.Proxy.checkout/2
然后,如果我这样做:
ExUnit.Case, async: true
setup do
on_exit fn ->
Repo.delete_all(ModelA)
Repo.delete_all(ModelB)
end
end
它工作,夹具数据在数据库中清理。但是如果我指定ExUnit.Case, async: true
,那么在运行所有测试时,我会遇到问题,因为测试会在MySQl上同时运行。
答案 0 :(得分:0)
我想您可能已经省略了一些错误消息。我无法肯定地说,但ecto2的一个常见错误是所有权混淆了。使用ecto2,现在有进程所有权机制,它跟踪哪个事务属于哪个进程,以便并发状态测试可以工作。
但是,您需要告诉 ecto该映射。 on_exit
在与调用者不同的进程中运行,因此当ecto不知道哪个事务拥有它时,它会尝试访问数据库,从而引发错误。
您可能需要告诉ecto(在setup
块中)设置沙箱的模式以允许任何进程在共享事务中访问数据库。由于您使用的是MySQL,因此您无需手动管理所有权,因为您无论如何都不会运行并发数据库测试,因此最好只为所有内容启用共享模式
你可以这样做:
setup do
Ecto.Adapters.SQL.Sandbox.mode(Perf.Repo, {:shared, self()})
end
我会将文档的一些相关部分粘贴到这篇文章中,但是我不会公正地对待这个部分的文档非常有用,详细和有用。 https://hexdocs.pm/ecto/Ecto.Adapters.SQL.Sandbox.html