请考虑以下代码:

class Child
  belongs_to :some_parent, optional: true
  def status
    some_parent&.calculate_status
  end
end

这是否足够琐碎到不 for each 场景编写单元测试,还是更好地编写场景,例如:

describe '#status' do 
  context 'when some_parent does not exist' do
    ## assume let/before block exist to properly set this up
    it 'returns nil' do
      expect(subject.status).to_be nil
    end
  end 

  context 'when some_parent exists' do
    ## assume let/before block exist to properly set this up
    it 'returns the value from some_parent' do
      expect(subject.status).to eql('expected status')
    end
  end
end

推荐答案

这并不一定是对此有一个事实答案的问题.您需要多少代码覆盖率由您自己决定.然而,如果我们将您的问题重新定义为Is there less code coverage when not testing the 100 state?,那么答案是yes,因为它们是两个不同的分支,每个分支都必须分别计算.

一百零二

some_parent&.calculate_status
#          ^ short circuits here and we branch to nil

When 100 exists:

some_parent&.calculate_status
#           ^ method evaluation occurs and we branch to the method

验证这一点的一种简单方法是使用simplecov进行测试.以下是一个可以验证这一点的示例应用程序:

# Gemfile

source 'https://rubygems.org'

gem 'rspec'
gem 'simplecov'
gem 'simplecov-console'
# app.rb

# We create the equivalent of your ++belongs_to++ call
# with these classes
class Parent
  def calculate_status
    "in parent"
  end
end

class Child
  attr_reader :some_parent

  def initialize(parent = nil)
    @some_parent = parent
  end

  def status
    @some_parent&.calculate_status
  end
end
# app_spec.rb

require "simplecov"
require "simplecov-console"

SimpleCov.start { enable_coverage :branch }
SimpleCov.formatter = SimpleCov::Formatter::Console

require_relative "app"

RSpec.describe "#status" do
  context "when some_parent does not exist" do
    it "returns nil" do
      expect(Child.new.status).to be nil
    end
  end

  context "when some_parent exists" do
    it "returns the value from some_parent" do
      expect(Child.new(Parent.new).status).to eq("in parent")
    end
  end
end

然后我们运行测试:

bundle exec rspec app_spec.rb
..

Finished in 0.00401 seconds (files took 0.09368 seconds to load)
2 examples, 0 failures


COVERAGE: 100.00% -- 9/9 lines in 1 files
BRANCH COVERAGE: 100.00% -- 2/2 branches in 1 branches

我们已经对这两个分支机构进行了测试,覆盖率为100%.如果我们告诉它只运行两个规范中的一个,我们会得到不同的结果:

bundle exec rspec app_spec.rb:14
Run options: include {:locations=>{"./app_spec.rb"=>[14]}}
.

Finished in 0.00141 seconds (files took 0.08878 seconds to load)
1 example, 0 failures


COVERAGE:  88.89% -- 8/9 lines in 1 files
BRANCH COVERAGE:  50.00% -- 1/2 branches in 1 branches

+----------+--------+-------+--------+---------+-----------------+----------+-----------------+------------------+
| coverage | file   | lines | missed | missing | branch coverage | branches | branches missed | branches missing |
+----------+--------+-------+--------+---------+-----------------+----------+-----------------+------------------+
|  88.89%  | app.rb | 9     | 1      | 3       |  50.00%         | 2        | 1               | 15[then]         |
+----------+--------+-------+--------+---------+-----------------+----------+-----------------+------------------+

或者另一种规格:

bundle exec rspec app_spec.rb:20
Run options: include {:locations=>{"./app_spec.rb"=>[20]}}
.

Finished in 0.00128 seconds (files took 0.08927 seconds to load)
1 example, 0 failures


COVERAGE: 100.00% -- 9/9 lines in 1 files
BRANCH COVERAGE:  50.00% -- 1/2 branches in 1 branches

+----------+--------+-------+--------+---------+-----------------+----------+-----------------+------------------+
| coverage | file   | lines | missed | missing | branch coverage | branches | branches missed | branches missing |
+----------+--------+-------+--------+---------+-----------------+----------+-----------------+------------------+
| 100.00%  | app.rb | 9     | 0      |         |  50.00%         | 2        | 1               | 15[else]         |
+----------+--------+-------+--------+---------+-----------------+----------+-----------------+------------------+

所以,如果你想要满分branch coverage,那就把两个规格都写下来.

Ruby相关问答推荐

RSpec:为什么 `instance_double` 可以与 StandardError 一起使用,但不能与其他异常类一起使用?

如何在 Shopify 脚本编辑器中显示数组值?

使用 Ruby,是否可以将 BigDecimal("1") / BigDecimal("3") 打印为 0.3333333333333... 到任意长度?

重写 Enum#inject 以在 Ruby 中将符号作为参数

如何判断一个对象在 Ruby 中是否可迭代?

有人可以解释 Ruby 在块中使用管道字符吗?

Simple_form:删除带有标签的内联复选框的外部标签

Ruby:p *1..10中的星号是什么意思

如何通过 Rack 提供静态文件?

在 Go (golang) 中编写一个 Ruby 扩展

有没有比 Rspec 的 `should_receive` 更少干扰的替代方法?

无法从同一网络上的另一台计算机访问本地 Sinatra 服务器

使用 Homebrew 安装 Ruby

无法在 macos-10.15.6 上Bundle 安装 puma 4.3.5 或 gem puma 与 ruby​​-2.6.6

如何使用 Ruby OptionParser 指定所需的switch (不是参数)?

如何通过匹配文本来 Select node

如何设置方法测试中使用的私有实例变量?

Sinatra 登录?

将整个文本文件作为单个字符串读取的合理方法是什么?

什么是 Ruby 1.9 标准 CSV 库?