You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ExUnit测试同进程内实现同步清理以替代on_exit

解决方案

最优方案:轻量重载test宏(无侵入、易维护)

你不需要修改现有任何测试用例代码,也不需要完整复制维护ExUnit的test宏实现,只需要在现有PersistenceTestCase的using块中对原生test宏做一层包裹,自动注入清理逻辑即可:

defmodule PersistenceTestCase do
  use ExUnit.CaseTemplate

  using do
    quote do
      # 先排除ExUnit默认导入的test宏
      import ExUnit.Callbacks, except: [test: 1, test: 2, test: 3]

      @doc """
      重载test宏,自动在测试体末尾注入同步清理逻辑
      接口和原生ExUnit test完全兼容,支持所有原生参数
      """
      defmacro test(message, var \\ quote(do: _), contents) do
        # 用try/after包裹原有测试体,确保清理逻辑无论测试结果如何都会执行
        wrapped_contents =
          quote do
            try do
              unquote(contents)
            after
              # 同步等待所有数据库连接释放,最多等待100ms
              Ecto.Adapters.SQL.Sandbox.disconnect_all(App.Repo, 100)
              # 如果有自定义的等待派生进程退出的逻辑,也可以放在这里
            end
          end

        # 调用原生test宏执行包裹后的测试逻辑
        ExUnit.Callbacks.test(unquote(message), unquote(var), unquote(wrapped_contents))
      end
    end
  end

  setup tags do
    # 原有setup逻辑保持不变
    Ecto.Adapters.SQL.Sandbox.mode(App.Repo, :manual)

    :ok = Ecto.Adapters.SQL.Sandbox.checkout(App.Repo)

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

    on_exit(fn ->
      Ecto.Adapters.SQL.Sandbox.mode(App.Repo, :auto)
    end)
  end
end

方案优势

  • 完全无侵入:所有已经use PersistenceTestCase的测试模块无需做任何修改,自动生效
  • 无竞态问题:清理逻辑在测试进程的上下文中同步执行,在测试进程退出前就完成所有数据库资源释放,完全避免Postgrex的连接报错
  • 维护成本极低:只是对原生test宏做轻量包裹,不需要复制维护ExUnit的宏源码,后续ExUnit版本升级几乎不会出现兼容问题

备用方案:无需修改宏的临时处理

如果暂时不愿意重载宏,也可以提高Postgrex的错误日志等级过滤该类报错,只需要在config/test.exs中添加配置:

config :logger, :handle_otp_reports, true
config :logger, :discard_threshold_for_error_logger, 1000
config :logger, :compile_time_purge_matching,
  [[level_lower_than: :critical], [application: :postgrex, message: &String.contains?(&1, "owner #PID")]]

该方案不会修复问题本身,只是过滤非致命的报错日志,适合临时快速解决CI报错的场景。

内容的提问来源于stack exchange,提问作者s3cur3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 03:33:01