将模拟模块还原为原始模块

Revert the mocked module back to the original

我正在使用 elixir,并且在使用 Mox 时看到 confusing/undesirable 行为。

我只想对单个测试模块使用模拟。假设我有 2 个测试。这是示例代码:

defmodule MyTest do
  setup_all do
    defmock(DateTimeMock, for: DateTimeApi)

    :ok
  end

  test "test1" do
    {:ok, expected_datetime, _} = DateTime.from_iso8601("2019-09-08T00:00:00.000000Z")
    expect(DateTimeMock, :utc_now, fn _ -> expected_datetime end)
  end

  test "test2" do
    expect(something else)
  end
end 

defmodule MyTest2 do
  setup_all do
    defmock(DateTimeMock, for: DateTimeApi)

    :ok
  end

  test "test1" do
  end

  test "test2" do
  end
end 

当 MyTest2 运行时,我会看到错误:(Mox.UnexpectedCallError) 没有定义预期

为单个测试定义模拟会“泄漏”并影响所有测试。

Mox 是否有办法在测试完成后将模拟模块还原为原始模块?

您可以在 setup 块中使用 on_exit 回调。设置函数的主要部分 运行s before 每次测试(因此它读取当前值),然后 on_exit 回调 运行s 每次测试后(因此它可以将事物设置回其原始值)。

defmodule MyTest do
  use ExUnit.Case

  setup do
    date_time_api = Application.get_env(:my_app, :date_time_api)
    on_exit(
      fn ->
        Application.put_env(:my_app, :date_time_api, date_time_api)
      end
    )
  end

  # Tests, fixtures follow...
end

请记住,您的代码遵循应用程序中可用的 运行 时间配置很重要,因此您的代码可能如下所示:

def utc_now do
  Application.get_env(:my_app, :date_time_api).utc_now()
end

具有类似

的相应配置值
# config/config.exs or env-specific config file
config :my_app, date_time_api: DateTimeApi

这就是让整个事情起作用的原因,因为该应用程序将在 运行-time 解析模块名称(即真实的或模拟的)。