查看源代码 mix test.coverage (Mix v1.16.2)

从导出的测试覆盖率构建报告。

在本模块文档中,我们将介绍 Elixir 中默认测试覆盖率的工作原理,并探讨如何将覆盖率结果导出到多个测试运行的汇总报告中。

行覆盖率

Elixir 使用 Erlang 的 :cover 作为其默认测试覆盖率工具。Erlang 覆盖率通过跟踪可执行代码行来实现。这意味着空白行、代码注释、函数签名和模式并不一定是可执行的,因此不会在覆盖率报告中跟踪。宏中的代码通常在编译时执行,因此可能无法覆盖。类似地,Elixir AST 字面量(如原子)也是不可执行的。

让我们看一个例子

if some_condition? do
  do_this()
else
  do_that()
end

在上面的示例中,如果您的测试同时执行 some_condition? == truesome_condition? == false,则所有分支都将被覆盖,因为它们都包含可执行代码。但是,以下代码

if some_condition? do
  do_this()
else
  :default
end

将永远不会标记 :default 分支为已覆盖,因为 else 分支中没有可执行代码。但是请注意,此问题不会发生在 casecond 上,因为 Elixir 能够在这样的特殊情况下将子句运算符 -> 标记为可执行的。

case some_condition? do
  true ->
    do_this()

  false ->
    :default
end

如果使用两种条件测试上面的代码,您应该看到两个分支中的条目都被标记为已覆盖。

最后,值得讨论的是,行覆盖率本身也存在局限性。例如,考虑以下代码

do_this() || do_that()

行覆盖率无法表达 do_this()do_that() 都已执行,因为只要执行了 do_this(),整行就被覆盖了。其他技术(如分支覆盖率)可以帮助发现这些情况,但目前默认覆盖率工具不支持它们。

总的来说,代码覆盖率可以成为发现代码缺陷(例如未覆盖的函数)的强大工具,但它也可能导致团队产生一种错误的安全感,因为即使使用最先进的覆盖率技术,100% 的覆盖率也不意味着所有不同的执行流程都已断言。您和您的团队需要自行决定要对代码覆盖率给予多少重视。

导出覆盖率

当您需要将多个测试运行的覆盖率汇总在一起时,可以使用此任务。让我们看一些例子。

示例:汇总分区运行

如果您将测试划分为多个运行,您可以像下面这样统一报告

$ MIX_TEST_PARTITION=1 mix test --partitions 2 --cover
$ MIX_TEST_PARTITION=2 mix test --partitions 2 --cover
$ mix test.coverage

这是因为 --partitions 选项会自动导出覆盖率结果。

示例:汇总所有伞形子项目中的覆盖率报告

如果您在伞形项目中运行 mix test.coverage,它会自动收集所有伞形子项目的导出覆盖率结果 - 只要覆盖率结果已导出,就像这样

# from the umbrella root
$ mix test --cover --export-coverage default
$ mix test.coverage

当然,如果您想实际对测试进行分区,您也可以这样做

# from the umbrella root
$ MIX_TEST_PARTITION=1 mix test --partitions 2 --cover
$ MIX_TEST_PARTITION=2 mix test --partitions 2 --cover
$ mix test.coverage

另一方面,如果您想要分区测试但每个应用程序都有独立的报告,您可以这样做

# from the umbrella root
$ MIX_TEST_PARTITION=1 mix test --partitions 2 --cover
$ MIX_TEST_PARTITION=2 mix test --partitions 2 --cover
$ mix cmd mix test.coverage

从伞形项目根目录运行 test.coverage 时,它将使用伞形项目根目录中的 :test_coverage 配置。

最后,请注意,覆盖率本身不会跨项目进行衡量。例如,如果项目 B 依赖于 A,并且 A 中的某些代码仅在项目 B 中执行,那么这些行将不会被标记为已覆盖,这一点很重要,因为这些项目应该独立开发和测试。

其他场景

您可能还有其他导出覆盖率的场景。例如,您可能将测试套件分为两个,一个用于单元测试,另一个用于集成测试。在这种情况下,您可以显式使用 --export-coverage 命令行选项,或者使用 mix.exs 文件中 :test_coverage 下的 :export 选项。