module Coverage

Coverage 为 Ruby 提供了代码覆盖率测量功能。此功能仍处于实验阶段,因此这些 API 在未来可能会发生变化。

注意:目前仅支持进程全局的代码覆盖率测量。您无法测量每个线程的代码覆盖率。

用法

  1. require “coverage”

  2. do Coverage.start

  3. require or load Ruby source file

  4. Coverage.result 将返回一个哈希,其中文件名作为键,代码覆盖率数组作为值。代码覆盖率数组为每一行提供解释器执行该行的次数。nil 值表示该行(如 elseend)的代码覆盖率被禁用。

示例

[foo.rb]
s = 0
10.times do |x|
  s += x
end

if s == 45
  p :ok
else
  p :ng
end
[EOF]

require "coverage"
Coverage.start
require "foo.rb"
p Coverage.result  #=> {"foo.rb"=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil]}

Lines Coverage

如果在启动代码覆盖率时未明确指定代码覆盖率模式,则将运行行代码覆盖率。它报告每一行的执行次数。

require "coverage"
Coverage.start(lines: true)
require "foo.rb"
p Coverage.result #=> {"foo.rb"=>{:lines=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil]}}

行代码覆盖率结果的值是一个数组,其中包含每一行被执行的次数。此数组中的顺序很重要。例如,此数组中的第一个元素,索引为 0,报告在此文件中的第 1 行在运行代码覆盖率时被执行的次数(在此示例中为一次)。

nil 值表示该行(如 elseend)的代码覆盖率被禁用。

Oneshot Lines Coverage

Oneshot 行代码覆盖率跟踪并报告正在运行的代码覆盖率期间执行的行。它不会报告某行被执行了多少次,只会报告它是否被执行过。

require "coverage"
Coverage.start(oneshot_lines: true)
require "foo.rb"
p Coverage.result #=> {"foo.rb"=>{:oneshot_lines=>[1, 2, 3, 6, 7]}}

Oneshot 行代码覆盖率结果的值是一个包含被执行的行号的数组。

Branches Coverage

Branches 代码覆盖率报告在每个条件语句中每个分支被执行的次数。

require "coverage"
Coverage.start(branches: true)
require "foo.rb"
p Coverage.result #=> {"foo.rb"=>{:branches=>{[:if, 0, 6, 0, 10, 3]=>{[:then, 1, 7, 2, 7, 7]=>1, [:else, 2, 9, 2, 9, 7]=>0}}}}

Branches 哈希中的每个条目都是一个条件语句,其值是另一个哈希,其中每个条目都是该条件语句中的一个分支。值是方法被执行的次数,键是关于分支的标识信息。

构成每个键以标识分支或条件语句的信息如下,从左到右:

  1. 分支或条件语句类型的标签。

  2. 唯一标识符。

  3. 它在文件中的起始行号。

  4. 它在文件中的起始列号。

  5. 它在文件中的结束行号。

  6. 它在文件中的结束列号。

Methods Coverage

Methods 代码覆盖率报告每个方法被执行的次数。

[foo_method.rb]
class Greeter
  def greet
    "welcome!"
  end
end

def hello
  "Hi"
end

hello()
Greeter.new.greet()
[EOF]

require "coverage"
Coverage.start(methods: true)
require "foo_method.rb"
p Coverage.result #=> {"foo_method.rb"=>{:methods=>{[Object, :hello, 7, 0, 9, 3]=>1, [Greeter, :greet, 2, 2, 4, 5]=>1}}}

Methods 哈希中的每个条目代表一个方法。此哈希中的值是方法被执行的次数,键是关于方法的标识信息。

构成每个键以标识方法的信息如下,从左到右:

  1. 类。

  2. 方法名。

  3. 方法在文件中的起始行号。

  4. 方法在文件中的起始列号。

  5. 方法在文件中的结束行号。

  6. 方法在文件中的结束列号。

All Coverage Modes

您还可以使用此快捷方式同时运行所有代码覆盖率模式。请注意,运行所有代码覆盖率模式不会同时运行 lines 和 oneshot_lines。这些模式不能同时运行。在这种情况下,将运行行代码覆盖率,因为您仍然可以使用它来确定某行是否被执行过。

require "coverage"
Coverage.start(:all)
require "foo.rb"
p Coverage.result #=> {"foo.rb"=>{:lines=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil], :branches=>{[:if, 0, 6, 0, 10, 3]=>{[:then, 1, 7, 2, 7, 7]=>1, [:else, 2, 9, 2, 9, 7]=>0}}, :methods=>{}}}