Рефакторинг спецификаций Rspec

Я пытаюсь очистить свои спецификации, поскольку они становятся чрезвычайно повторяющимися.

У меня есть следующая спецификация

  describe "Countries API" do 
    it "should render a country list" do
      co1 = Factory(:country)
      co2 = Factory(:country)
      result = invoke :GetCountryList, "empty_auth"

      result.should be_an_instance_of(Api::GetCountryListReply)
      result.status.should be_an_instance_of(Api::SoapStatus)
      result.status.code.should eql 0
      result.status.errors.should be_an_instance_of Array
      result.status.errors.length.should eql 0
      result.country_list.should be_an_instance_of Array
      result.country_list.first.should be_an_instance_of(Api::Country)
      result.country_list.should have(2).items
    end
    it_should_behave_like "All Web Services"
    it "should render a non-zero status for an invalid request"
  end

Блок кода, проверяющий статус, появится во всех моих спецификациях для 50-60 API. Моя первая мысль состояла в том, чтобы перенести это в метод, и этот рефакторинг, безусловно, делает вещи намного суше:

def status_should_be_valid(status)
    status.should be_an_instance_of(Api::SoapStatus)
    status.code.should eql 0
    status.errors.should be_an_instance_of Array
    status.errors.length.should eql 0
end

describe "Countries API" do 
    it "should render a country list" do
      co1 = Factory(:country)
      co2 = Factory(:country)
      result = invoke :GetCountryList, "empty_auth"

      result.should be_an_instance_of(Api::GetCountryListReply)
      status_should_be_valid(result.status)
      result.country_list.should be_an_instance_of Array
      result.country_list.first.should be_an_instance_of(Api::Country)
      result.country_list.should have(2).items
    end
  end

Это работает, однако я не могу отделаться от ощущения, что это не «правильный» способ сделать это, и я должен использовать общие спецификации, однако, глядя на метод определения общих спецификаций, я не могу легко понять, как бы я реорганизовал этот пример для использования общая спец.

Как бы я сделал это с общими спецификациями и без повторного запуска относительно дорогостоящего блока в начале, а именно

  co1 = Factory(:country)
  co2 = Factory(:country)
  result = invoke :GetCountryList, "empty_auth"

person Steve Weet    schedule 29.04.2010    source источник


Ответы (1)


Вот один из вариантов, использующий новую "субъективную" функцию RSpec. Обратите внимание, что это запустит блок before :all дважды, по одному разу для каждого вложенного блока «describe». Если это окажется слишком медленным, вы можете сгладить ситуацию за счет невозможности использовать синтаксис «субъект» для общих примеров состояния (поскольку субъект применяется ко всему блоку описания, в котором он используется).

shared_examples_for "valid status" do
  it { should be_an_instance_of(Api::SoapStatus) }
  its(:code) { should eql(0) }
  its(:errors) { should be_an_instance_of(Array) }
  its(:errors) { should be_empty }
end

describe "Countries API" do
  before :all do
    co1 = Factory(:country)
    co2 = Factory(:country)
    @result = invoke :GetCountryList, "empty_auth"
  end

  subject { @result }
  it { should be_an_instance_of(Api::GetCountryListReply) }
  its(:country_list) { should be_an_instance_of (Array) }
  it "should have countries in the country list" do
    @result.country_list.each {|c| c.should be_an_instance_of(Api::Country)}
  end
  its(:country_list) { should have(2).items }

  describe "result status" do
    subject { @result.status }
    it_should_behave_like "valid status"
  end
end
person Greg Campbell    schedule 29.04.2010
comment
Пара странных проблем с этим. Прежде чем :all выдает следующую ошибку NoMethodError in 'AdminlwController Countries API before(:all)' undefined method recycle!' for nil:NilClass` Переход на before(:each) идет дальше, но borks на its(:country_list) думаю, что я начну новый вопрос. - person Steve Weet; 29.04.2010
comment
Да, очевидно, у меня нет доступа к вашему коду (я провел этот тест с некоторыми полностью смоделированными объектами, чтобы убедиться, что синтаксис правильный, но это все), поэтому могут быть проблемы, о которых я не знаю. - person Greg Campbell; 29.04.2010
comment
Кстати, какую версию RSpec вы используете? Функциональность its() была добавлена ​​в версии 1.2.9. - person Greg Campbell; 30.04.2010
comment
Я обновился до последней версии (1.3.0), когда у меня впервые начались проблемы. - person Steve Weet; 30.04.2010