2013-08-02 1 views
4

Я работаю, пытаясь сохранить мои файлы спецификаций настолько чистыми, насколько это возможно. Использование драгоценного камня «toa» и написание индивидуальных шаблонов, которые следуют одному и тому же шаблону.Очистить Rspec matcher для изменения (Model,: count) .by (1)

Мой вопрос заключается в создании пользовательского совпадения, которое обертывало бы expect{ post :create ... }.to change(Model, :count).by(1) и могло использоваться в тех же группах примеров с другими помощниками 'toa'. Подробности ниже:

Выборочная Искателя (упрощенный)

RSpec::Matchers.define :create_a_new do |model| 
    match do |dummy| 
    ::RSpec::Expectations::ExpectationTarget.new(subject).to change(model, :count).by(1) 
    end 
end 

Рабочий пример

describe 'POST create:' do 
    describe '(valid params)' do 
    subject { -> { post :create, model: agency_attributes } } 
    it { should create_a_new(Agency) } 
    end 
end 

Эта работа OK до тех пор, как я использую subject лямбда, и мой согласовани является единственным в группе примеров.

непрохождения примеры

непрохождения Пример 1

Добавление большего количества примеров в той же группе делает другой Matcher неудачу, потому что subject теперь лямбда вместо экземпляра контроллера.

describe 'POST create:' do 
    describe '(valid params)' do 
    subject { -> { post :create, model: agency_attributes } } 
    it { should create_a_new(Agency) } 
    it { should redirect_to(Agency.last) } 
    end 
end 

В противном случае пример 2

В 'Shoulda' Искателя, чтобы я определить before блок, но это стало несовместимым с моей пользовательской согласовани

describe 'POST create:' do 
    describe '(valid params)' do 
    before { post :create, agency: agency_attributes } 
    it { should create_a_new(Agency) } 
    it { should redirect_to(Agency.last) } 
    end 
end 

Ожидаемый результат

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

Спасибо за чтение

ответ

5

Я не думаю, что есть способ, вы можете получить ваши неудовлетворительные примеры прохождения.

Это потому, что change действительно нуждается в лямбда, так как он должен выполнять ваш счет дважды (один раз до и один раз после его вызова). Вот почему я склонен не использовать его (или использовать его в изоляции контекста).

То, что я обычно делаю, вместо того, чтобы использовать count Искателя, проверяет три вещи:

  • Запись сохраняется. Если я присвою модель @model, тогда я использую expect(assigns(:model)).to be_persisted
  • Запись является экземпляром ожидаемой модели (хотя может показаться нецелесообразной, она довольно описательна при использовании ИППП). expect(assigns(:model)).to be_a(Model).
  • Проверить последняя запись в БД такой же, как тот, который я просто создать `ожидать (правопреемники (: модель)). Эквализировать (Model.last)` `

И это так, как я обычно тест change, не используя его. Конечно, теперь вы можете создать свой собственный счетчик

RSpec::Matchers.define :create_a_new do |model| 
    match do |actual| 
    actual.persisted? && 
     actual.instance_of?(Participant) && 
     (Participant.last == actual) 
    end 
end 
+0

Интересно, спасибо за разъяснение. Позвольте мне проверить это немного, и я вернусь с вами. – Benj

+0

Еще одна вещь, которую я пытаюсь в последнее время, заключается в инкапсуляции действия ('post: create, params, session') в методе. Не уверен, если я продолжу это делать, но в некоторых случаях это может стоить того. – Serabe

+0

Это была одна из моих попыток, а также 'set (: action) {post: create ...}', но я не нашел способ быть действительно СУХОЙ, потому что у меня получился вонючий код вроде 'before {if example. метаданные [: skip_before]; action end} ' – Benj