6

我有一段看起来像这样的代码:

Repo.transaction(fn ->
  Repo.query!("set transaction isolation level serializable;")

  # do some queries

end)

在我的测试套件中,我不断遇到错误:

(Postgrex.Error) ERROR 25001 (active_sql_transaction): SET TRANSACTION ISOLATION LEVEL must be called before any query

我想知道我是否在做一些根本性的错误,或者我是否缺少有关测试环境的某些东西。

谢谢!

4

2 回答 2

4

不确定您是否仍在寻找答案,但我找到了一个很好的解决方案。对于这种情况,我有这样的设置块:

setup tags do
  :ok =
    if tags[:isolation] do
      Sandbox.checkout(Repo, isolation: tags[:isolation])
    else
      Sandbox.checkout(Repo)
    end

    unless tags[:async] do
      Sandbox.mode(Repo, {:shared, self()})
    end

    :ok
  end

然后在可序列化事务路径中的测试中,您必须使用“可序列化”标记它,如下所示:

@tag isolation: "serializable"
test "my test" do
  ...
end

这将让您运行在路径中可序列化的测试并仍然使用沙箱。

于 2019-08-02T14:41:16.913 回答
2

问题是出于测试目的,所有测试都包含在事务中,因此它们可以回滚,这样您就不会用大量旧测试数据污染数据库。这可能会导致本应通过的失败和本应失败的通过,具体取决于您编写测试的方式。

您可以解决它,但它会再次污染您的测试数据库,您必须自己清理它:

setup do 
  [Other set up stuff]
  Ecto.Adapters.SQL.Sandbox.checkin(MyApp.Repo) #This closes any open transaction, effectively.
  Ecto.Adapters.SQL.Sandbox.checkout(MyApp.Repo, [sandbox: false]) # This opens a new transaction without sandboxing. 
end

如果您没有设置,则此设置任务将与您的失败测试一起进入测试文件。如果您不进行checkin调用,您将(很可能)在设置事务级别之前收到有关其他查询运行的错误,因为您在测试之前插入了一些东西。

看到这里有人基本上提出了同样的问题。

于 2019-01-13T17:19:30.037 回答