考虑对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

所以第一个测试失败了,而第二个测试通过了。为什么会这样?

最佳答案

第二个测试通过了,因为它没有测试任何东西。它不包含任何期望(即调用shouldshould_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

10-04 16:41