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

时间:2014-01-06 11:45:16

标签: elixir

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

4 个答案:

答案 0 :(得分:82)

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

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

答案 1 :(得分:11)

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

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

  # This will be exported for tests
  defp bar() do
  ... code ...
  end
end

答案 2 :(得分:6)

可以使用宏来改变功能的可见性,具体取决于环境:

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

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

Source

答案 3 :(得分:0)

即使在使用ExUnit进行测试的情况下,也无法从其模块外部调用私有函数。

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

1)将要测试的功能公开,但用RedirectMatch 301 ^/faqs/(.+)$ https://www.example.com/$1 进行标记,这意味着它不属于模块的公共API。

2)或者,如果您要测试的功能是@doc false,则在同一模块中创建一个defp foo,该模块将接受您想要在测试期间改变的参数,并将其适应于def test_foo期望,并最终调用foo。您也只能在这样的测试过程中生成特殊的测试功能

foo

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

当然,正如其他人提到的那样,一般规则是避免测试私有功能,但是有时测试它们是简化测试并扩大测试范围的一种方式。

良好的编码!