考虑以下代码:
class Child
belongs_to :some_parent, optional: true
def status
some_parent&.calculate_status
end
end
这是否足够简单,以至于不为每个场景编写单元测试,或者编写诸如以下场景更好:
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
2条答案
按热度按时间xxb16uws1#
这不一定是一个事实的答案。您需要多少代码覆盖率取决于您。但是,如果我们将您的问题重新定义为 * 当不测试
nil
状态时,代码覆盖率是否更低?* 那么答案是是,因为它们是两个不同的分支,每个分支都必须单独评估。当
some_parent
为nil
时:some_parent
存在时:验证这一点的一个简单方法是使用simplecov进行测试。下面是一个示例应用程序,可以验证它:
然后我们运行测试:
我们已经测试了这两个分支,并有100%的覆盖率。如果我们告诉它只运行两个规范中的一个,我们会得到不同的结果:
另一个spec:
因此,如果你想要完整的 * 分支覆盖 * 然后写两个规范。
kyxcudwk2#
正如在其他地方提到的,您的团队的代码覆盖率标准由您来确定。你需要理解收益递减的论点和“你希望我不要测试什么”的论点,然后打电话。
然而,你的问题有一个不同的方面值得注意:* 使用安全导航操作符的代码是否比不使用它的代码更复杂?*
安全导航操作符被添加到Ruby中,以减少违反得墨忒耳定律所导致的
undefined method 'x' for nil:NilClass (NoMethodError)
错误。由于在ActiveRecord中将查询和子句附加在一起的方式,这些冲突在Rails应用程序中很常见。从某种意义上说,操作符可以减少代码。而且,一般来说,代码越少,复杂性越低。但是,让我们看看这个和其他两个方法,并比较复杂性。如果我们将安全导航与使用
&&
的旧方法和第三种方法(使用NullObject
模式)进行比较:我们从flog中得到以下内容:
所以,是的,孤立地说,安全导航操作员是最不复杂的解决方案。但是,当您考虑到
Child
类的客户机现在还必须处理nil
时,整个复杂性场景就会发生变化。让我们添加一个ClientOfChild
类,看看它的复杂性:这是一个类:
在这段代码中,包含和不包含安全导航操作符的代码都必须处理
nil
,但基于NullObject
的代码不需要。以下是Flog:
现在,看看我们得到的每条路径的总flog:
因为这是对真实的代码的过度简化,所以flog中的差异很小。但是,总的赢家是
NullObject
模式。你会发现,方法越复杂,这些数字就会增长得越远。出于这个原因,为了在代码中不违反Demeter定律,我选择了
NullObject
模式,而不是使用安全导航操作符(ActiveReccord查询除外,因为,嗯。.. Rails)。