63

定义的函数defp不会被导出,所以我不能在模块以外的地方执行它们。

4

4 回答 4

105

不,没有办法通过 ExUnit 测试它们。

我个人避免测试私有函数,因为通常您最终会测试实现而不是行为,并且一旦您需要更改代码,这些测试就会失败。相反,我通过公共函数测试预期的行为,将它们分成小的、一致的块。

于 2014-01-06T12:05:21.973 回答
22

在您的模块定义中,您可以使用指令在测试环境中@compile导出您的私有函数。

defmodule Foo do
  @compile if Mix.env == :test, do: :export_all

  # This will be exported for tests
  defp bar() do
  ... code ...
  end
end
于 2017-05-23T02:55:24.840 回答
9

可以使用宏根据环境更改函数的可见性:

defmacro defp_testable(head, body \\ nil) do
  if Mix.env == :test do
    quote do
      def unquote(head) do
        unquote(body[:do])
      end
    end
  else
    quote do
      defp unquote(head) do
        unquote(body[:do])
      end
    end
  end
end

然后您可以将函数公开给您的测试,如下所示:

defp_testable myfunc do
  ...
end

出于何塞的回答中给出的原因,我建议谨慎使用它。它不能替代测试模块的外部行为。不过,它在某些情况下可能很有价值。

来源

于 2017-12-01T17:08:43.320 回答
2

不能从其模块外部调用私有函数,即使在使用 ExUnit 进行测试的上下文中也是如此。

其他人建议使用复杂的方法来公开私有函数进行测试,因此我建议另外两个看起来更简单的方法:

1) 将要测试的函数设为公开,但用 标记@doc false,这意味着它不是模块的公共 API 的一部分。

2) 或者,如果您要测试的函数是在同一个模块中defp foo创建一个def test_foo, ,它会在测试期间接受您想要改变的参数,使它们适应foo预期的内容,最后调用foo. 您也可以仅在这样的测试期间生成您的特殊测试功能

  if Mix.env == :test do
    def test_foo ...
  end

这些替代方案中的任何一个都更简单,并且在您的项目中不需要额外的依赖项。

当然,正如其他人提到的,一般规则是避免测试私有函数,但有时测试它们是简化测试并提高测试覆盖率的方法。

好编码!

于 2020-01-25T13:16:56.043 回答