Ruby проверяет vs to_s в Rspec - PullRequest
       3

Ruby проверяет vs to_s в Rspec

2 голосов
/ 12 февраля 2011

Рассмотрим следующий тест для 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

Итак, первый тест не пройден, тогда как второй тест пройден. Почему это так?

Ответы [ 2 ]

3 голосов
/ 12 февраля 2011

Второй тест пройден, потому что он ничего не проверяет. Он не содержит никаких ожиданий (т.е. вызов 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
2 голосов
/ 12 февраля 2011

Я думаю, что ваш тест должен быть следующим (и они оба пройдут). Первый пропускает фактический вызов to_s, а второй пропускает .should:

describe RspecTest do
  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
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...