Elixir/ExUnit:可以将上下文从测试用例传递到拆解/清理方法(on_exit)吗?

use*_*184 13 unit-testing functional-programming elixir teardown ex-unit

问题

我想测试一个与主机系统交互的Elixir模块,并且具有副作用的方法.对于这个问题并保持简短,假设它是几个目录的创建.这些目录当然应该在运行测试后删除,如果测试(很长时间)由于任何原因(坏的模块代码,错误的测试代码等)而失败.

我想知道如何最好/最优雅地解决这个清理步骤.我查看了ExUnit.Callbacks.on_exit/2的文档,但它的示例仅用于设置和简单拆解(不涉及传递状态).我也在线搜索,但没有发现任何有用的东西,所以可能是我的想法本身并不好 - 我也愿意接受重构问题的建议.

defmodule SimpleTest do
  use ExUnit.Case

  setup_all do
    ts = Time.utc_now |> Time.to_string
    {:ok, [timestamp: ts]}
    # paths to be cleaned are not yet known here
  end

  test "first test", context do
    path = "/tmp/dir" <> context[:timestamp]
    assert :ok == SimpleModule.mkdir(path)
    assert :eexist == SimpleModule.mkdir(path)
    # [path] should be passed on to cleanup
  end

  test "second test", context do
    path = "/tmp/dir" <> context[:timestamp]
    path2 = "/tmp/dir2" <> context[:timestamp]
    SimpleModule.mkdir(path)
    SimpleModule.mkdir(path2)
    assert File.exists?(path)
    assert File.exists?(path2)
    # [path, path2] should be passed on to cleanup
  end

  defp cleanup(context) do
    Enum.each(context[:dirs], fn(x) -> File.rmdir(x) end)
  end
end

defmodule SimpleModule do
  def mkdir(path) do
    File.mkdir(path)
  end
end
Run Code Online (Sandbox Code Playgroud)

可能的解决方案?

我现在想要cleanup/1在每次测试后添加一个要删除的目录列表的调用.以下想法是我尝试过的事情:

  • 在每个测试结束时直接调用函数:适用于简单的情况,但如果测试用例无休止地循环,它将被终止并且不再进行清理.
  • on_exit(fn -> cleanup(context) end)在每个测试中调用更新的上下文:这似乎有效,但我无法确定是否推荐它,如果它将调用放在测试中(开始/结束)会有所不同.
  • 调用on_exit(fn -> cleanup(context) end)setup context功能:文件这样做,但我不知道如何将任何新的状态/上下文传递给它.它似乎只有在设置函数中已经完全定义了所有上下文时才有用.

也许我也在过度思考这个问题...我只是有一些糟糕的调试经验,不完全清理并导致无休止的递归(应该已经被我的代码捕获,但还没有),所以我只是想确保我这样做正确的事情,并以正确的方式学习它.除了那些测试,Elixir到目前为止是一个非常愉快和完美的体验!

lei*_*ifg 9

在这种特殊情况下,我只会on_exit在您的 setup 函数(您的第三个解决方案)中注册回调。

不是单独删除路径,而是删除父目录:

@test_dir "/tmp/base_test"

setup do
  File.mkdir(@test_dir)

  on_exit fn ->
    File.rm_rf @test_dir
  end
end
Run Code Online (Sandbox Code Playgroud)

然后@test_dir在您的测试中用作您的基本目录