有没有办法在Elixir的ExUnit中测试模块中的私有函数?

Noa*_*ues 54 elixir

定义的函数defp不会导出,因此我无法在模块以外的位置执行它们.

Jos*_*lim 87

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

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

  • 仅供参考,无论语言或测试库如何,这都是一个很好的建议. (25认同)
  • 对不起被打断编辑这个.在全球范围内同意,但认为某些私有功能可以从重构目的的测试中受益. (14认同)
  • @tompave我想你在某些情况下是正确的,但是我想为我的库用户提供对该实用程序模块的限制访问,但这看起来有点复杂.我仍然觉得重构用例被低估了. (5认同)
  • 我倾向于尊重地不同意:有两种测试方法。在行为上 (3认同)
  • @lab419 您可以将“@moduledoc false”添加到模块中,以将其及其函数从文档中排除。不过,这些函数仍然是可调用的。我在你的偏好和将函数公开的想法之间犹豫不决。从某种意义上说,它们并不有趣,想要测试函数但不将它们作为应用程序或库的公共 API 的一部分公开似乎是合理的。也许,在实践中,记录一个模块或函数不是“公共 API”的一部分就足够了,即可能会被删除或其他“重大更改”。 (3认同)

Mic*_*hop 13

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

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

  # This will be exported for tests
  defp bar() do
  ... code ...
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 更新:这将在Elixir 1.5中发出警告,因此它可能不是最佳方式. (2认同)

acj*_*acj 7

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

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
Run Code Online (Sandbox Code Playgroud)

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

defp_testable myfunc do
  ...
end
Run Code Online (Sandbox Code Playgroud)

我建议谨慎使用这个问题,理由是José的回答.它不能替代测试模块的外部行为.不过,它在某些情况下可能很有价值.

(来源)