问题描述
假设你有一些类似的课程
class Foo
...
public def methodA
x = methodB(true)
# other operations (assume x is not the return value of methodA)
end
private def methodB(arg)
if arg
return 1
else
return 0
end
end
end
当您为 methodA
编写单元测试时,您想检查 x
是否被分配了正确的值,这意味着您必须检查对 methodB
的调用是否返回1
如您所料。
您将如何在 rspec 中进行测试?
现在我有(在 How to test if method is called in RSpec but do not override the return value 的帮助下)
@foo = Foo.new
expect(@foo).to receive(:methodB).with(true).and_call_original
但是我不知道如何验证methodB
的实际返回值。
解决方法
我认为您可以调用私有方法而不是嘲笑?
@foo = Foo.new
result = foo.send(:methodB,true)
expect(result).to eq 1
这基本上是直接测试私有方法。有些人不喜欢这样做,但如果它有很多逻辑,有时直接测试它会更容易。我同意@spickermann 的观点,通常最好测试公共方法并将私有方法的实现细节排除在规范之外。
,不要在一个单元测试中测试多种方法
您这样做是错误的,因为您在两种不同的方法之间创建了不必要的依赖关系。相反,您应该重构您的代码,以便:
- x 是 #methodA 的参数,
- x、@x 或 @@x 是一个可供 methodA 访问的变量,您可以将其设置为您想要的任何期望值,或
- 为这个单元测试剔除#methodB。
作为最后一个例子:
describe Foo do
describe 'methodA' do
it 'does something when methodB returns 1' do
# stub the default subject,which is Foo.new
allow(subject).to receive(:methodB) { 1 }
expect(subject.methodA).to eq('foo bar baz')
end
end
end
此代码未经测试,因为您发布的代码不是完整的、可验证的示例。虽然您最好重构您的代码,这样您根本就不会测试嵌套的依赖项,但使用 test doubles or method stubs 当然是可行的选择。