defp
定义的函数没有被导出,因此我无法在模块以外的地方执行它们。
不,无法通过ExUnit测试私有函数。
个人而言,我避免测试私有函数,因为通常会测试实现而不是行为,这些测试在需要更改代码时很容易失败。相反,我通过公共函数测试期望的行为,将其分解成小而一致的块。
@moduledoc false
来将其和其中的函数排除在文档之外。这些函数仍然可以被调用。我有些犹豫,不知道要按你的喜好还是直接将这些函数公开。从某种意义上说,它们并不重要,因此希望测试这些函数但不将其作为应用程序或库的公共 API 的一部分公开似乎是合理的。也许,实际上,说明一个模块或函数不是公共 API 的一部分,并可能会被删除或进行其他“破坏性更改”,这样就足够了。 - Kenny Evitt@compile
指令将您的私有函数仅导出到测试环境中。defmodule Foo do
@compile if Mix.env == :test, do: :export_all
# This will be exported for tests
defp bar() do
... code ...
end
end
可以使用宏来根据环境改变函数的可见性:
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é的回答。它不是测试模块外部行为的替代品。然而,在某些场景下是有价值的。
(源代码)
私有函数不能从其模块外部调用,即使在使用ExUnit进行测试的情况下也是如此。
其他人建议采用复杂的方式来暴露私有函数以供测试,因此我建议采用以下两种方法,它们似乎更简单:
1)将要测试的函数公开,但标记为@doc false
,这意味着它不是您的模块的公共API的一部分。
2)或者,如果你想测试的函数是defp foo
,那么在同一个模块中创建一个def test_foo
,并在测试期间对你想要变化的参数进行适应,以符合foo
的要求,并最终调用foo
。你也可以像这样仅在测试期间生成你的特殊测试函数。
if Mix.env == :test do
def test_foo ...
end
defp
,而在 TEST 环境中扩展为def
? - TalkLittle