rspec + shoulda: setting up data

笑着哭i 提交于 2019-12-13 01:58:18

问题


I have the following test. There are three it blocks. The first one doesn't use shoulda unlike the other two.

If I don't use the before block with post :create, product: attrs then the first test fails as expected. But If I put the before block there then the first test fails, but the other two pass. I have a uniqueness validation on product name, but that shouldn't be the problem as I'm using sequence with factory.

What should I do? How should I generally setup the data for testing when there are rspec and shoulda matchers present at the same time?

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

factories

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

回答1:


You can't have it both ways. If you execute the method you are testing in the before, then you can't execute it again to see if it changes the Product count. If you don't execute it in your before, then you must execute it in your example and therefore can't use the is_expected one liner format.

There are a variety of alternatives. Here is one that incorporates the execution of the method into all the examples.

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


来源:https://stackoverflow.com/questions/36827856/rspec-shoulda-setting-up-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!