Ecto 2.0 + MySQL:在测试中清理灯具

时间:2016-08-10 10:57:48

标签: mysql elixir phoenix-framework ecto

我在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上同时运行。

1 个答案:

答案 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