考虑对rspec
进行以下测试:
class RspecTest
def initialize
end
def to_s
"foo"
end
end
describe RspecTest do
it "should return foo (to_s)" do
RspecTest.new.should == "foo"
end
it "should return foo (inspect)" do
RspecTest.new.inspect == "foo"
end
end
当通过
rspec
测试时:%: rspec rspec_test.rb
F.
Failures:
1) RspecTest should return foo (to_s)
Failure/Error: RspecTest.new.should == "foo"
expected: "foo"
got: foo (using ==)
Diff:
# ./rspec_test.rb:13:in `block (2 levels) in <top (required)>'
Finished in 0.00059 seconds
2 examples, 1 failure
所以第一个测试失败了,而第二个测试通过了。为什么会这样?
最佳答案
第二个测试通过了,因为它没有测试任何东西。它不包含任何期望(即调用should
或should_not
)。它不能失败,因为没有什么可以失败。
第一个测试失败,因为您断言RspecTest
的实例等于字符串'foo'
。这不可能是真的。如果这两个物体甚至不是同一种物体,它们怎么可能相等呢?
从测试的描述来看,实际上并不是要测试RspecTest
的实例是否等于字符串'foo'
,而是要测试实例方法to_s
的返回值是否等于字符串'foo'
。但是,您从不在任何地方调用to_s
。
让我们先解决这两个明显的问题。现在,我们有一个这样的测试:
it 'should return foo (to_s)' do
RspecTest.new.to_s.should == 'foo'
end
it 'should return foo (inspect)' do
RspecTest.new.inspect.should == 'foo'
end
两个
RspecTest.new
调用之间存在一些不必要的重复,因此让我们通过简单地将RspecTest.new
设置为默认主题来解决这个问题: subject { RspecTest.new }
it 'should return foo (to_s)' do
subject.to_s.should == 'foo'
end
it 'should return foo (inspect)' do
subject.inspect.should == 'foo'
end
实际上,如果您不提供显式主题,那么rspec将沿着嵌套的
describe
块链一直走,直到找到一个类,并只调用该类的new
方法来提供主题。所以,我们可以删除subject
声明: it 'should return foo (to_s)' do
subject.to_s.should == 'foo'
end
it 'should return foo (inspect)' do
subject.inspect.should == 'foo'
end
就我个人而言,我更喜欢让rspec自己提供示例名称,这样示例名称和实际示例代码就不会失去同步,所以我可能会这样写:
describe RspecTest do
describe '#to_s' do
it { subject.to_s.should == 'foo' }
end
describe '#inspect' do
it { subject.inspect.should == "foo" }
end
end
结果是:
RspecTest
#to_s
should == "foo"
#inspect
should == "foo"
Finished in 0.16023 seconds
2 examples, 0 failures
最后但并非最不重要的是,您的初始化程序实际上什么也没做,所以您不需要它。总之,我的版本是这样的:
class RspecTest
def to_s; 'foo' end
end
describe RspecTest do
describe '#to_s' do
it { subject.to_s.should == 'foo' }
end
describe '#inspect' do
it { subject.inspect.should == "foo" }
end
end