2016-04-24 2 views
1

У меня есть следующее испытание. Есть три блока it. Первый не использует shoulda в отличие от двух других.rspec + shoulda: настройка данных

Если я не использую блок before с номером post :create, product: attrs, то первое испытание завершится неудачно, как ожидалось. Но если я поставлю блок before, тогда первый тест не удастся, но остальные два пройдут. У меня есть проверка уникальности имени продукта, но это не должно быть проблемой, поскольку я использую последовательность с фабрикой.

Что мне делать? Как я обычно настраиваю данные для тестирования, когда одновременно присутствуют контроллеры rspec и shoulda?

describe "when user logged in" do 
    before(:each) do 
    login_user #logged in user is available by calling @user 
    end 

    context "POST create" do 
    context "with valid attributes" do 
     let!(:profile) { create(:profile, user: @user) } 
     let!(:industry) { create(:industry) } 
     let!(:attrs) { attributes_for(:product, user_id: @user.id, industry_ids: [ industry.id ]).merge(
      product_features_attributes: [attributes_for(:product_feature)], 
      product_competitions_attributes: [attributes_for(:product_competition)], 
      product_usecases_attributes: [attributes_for(:product_usecase)] 
     ) } 

     it "saves the new product in the db" do 
     expect{ post :create, product: attrs }.to change{ Product.count }.by(1) 
     end 

     #If I don't use this the 2 tests below fail. If I use it, then the test above fails. 
     # before do 
     # post :create, product: attrs 
     # end 

     it { is_expected.to redirect_to product_path(Product.last) } 
     it { is_expected.to set_flash.to('Product got created!') } 
    end 
    end 
end 

фабрики

factory :product, class: Product do 
    #name { Faker::Commerce.product_name } 
    sequence(:name) { |n| "ABC_#{n}" } 
    company { Faker::Company.name } 
    website { 'https://example.com' } 
    oneliner { Faker::Lorem.sentence } 
    description { Faker::Lorem.paragraph } 
    user 
end 
+0

Вы считали, что используете различные блоки контекста? Это позволит вам иметь отдельный блок перед блоками. –

+0

Петр, я сделал. Я просто не знаю, как правильно это сделать. В верхней части этого я хотел бы понять корень проблемы. –

ответ

1

Вы не можете иметь его в обоих направлениях. Если вы выполняете метод, который вы тестируете в before, то вы не можете выполнить его снова, чтобы увидеть, изменит ли он счет Product. Если вы не выполнили его ранее, вы должны выполнить его в своем примере и, следовательно, не можете использовать формат одного лайнера is_expected.

Существует множество альтернатив. Вот тот, который включает выполнение метода во все примеры.

describe "when user logged in" do 
    before(:each) do 
    login_user #logged in user is available by calling @user 
    end 

    describe "POST create" do 
    subject(:create) { post :create, product: attrs } 
    context "with valid attributes" do 
     let!(:profile) { create(:profile, user: @user) } 
     let!(:industry) { create(:industry) } 
     let!(:attrs) { attributes_for(:product, user_id: @user.id, industry_ids: [ industry.id ]).merge(
      product_features_attributes: [attributes_for(:product_feature)], 
      product_competitions_attributes: [attributes_for(:product_competition)], 
      product_usecases_attributes: [attributes_for(:product_usecase)] 
     ) } 

     it "saves the new product in the db" do 
     expect{ create }.to change{ Product.count }.by(1) 
     end 

     it("redirects") { expect(create).to redirect_to product_path(Product.last) } 
     it("flashes") { expect(create).to set_flash.to('Product got created!') } 
    end 
    end 
end 
+0

Питер, спасибо за ответ! Разве вы не знаете хорошего ресурса, в котором различные решения сочетаются или сравниваются друг с другом? Я много читал о 'let',' subject', 'before',' rspec matchers' и 'shoulda matchers', но все ресурсы объясняли их изолированно. Когда дело доходит до их использования, это может быть довольно запутанным. –

+0

Питер, также см. Мой предыдущий комментарий. Вы уверены, что можете передать блок с помощью '{}' like 'it 'redirects' {expect (create) .to redirect_to product_path (Product.last)}'? По какой-то причине он работает только с 'do' +' end' для меня. –

+0

Вы абсолютно правы в фигурных скобках. Вы не можете пропустить круглые скобки при вызове метода и добавить блок. Вы должны либо использовать 'do'' end' для блока, либо включать круглые скобки. Я соответствующим образом обновил ответ. –

Смежные вопросы