【问题标题】:rspec + shoulda: setting up datarspec + shoulda:设置数据
【发布时间】:2016-04-24 19:28:12
【问题描述】:

我有以下测试。共有三个 it 块。与其他两个不同,第一个不使用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

【问题讨论】:

  • 您是否考虑过使用不同的上下文块?这将允许您有单独的前块。
  • 彼得,我做到了。我只是不知道正确的方法是什么。最重要的是,我想了解问题的根源。

标签: ruby-on-rails testing rspec shoulda


【解决方案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

【讨论】:

  • 彼得,感谢您的回答!难道你不知道一个很好的资源,其中不同的解决方案被组合或相互比较?我已经阅读了很多关于letsubjectbeforerspec matchersshoulda matchers 的内容,但所有资源都孤立地解释了它们。当涉及到一起使用它们时,可能会很混乱。
  • 彼得,请参阅我的上一条评论。你确定你可以通过{ }it "redirects" { expect(create).to redirect_to product_path(Product.last) } 这样的块吗?出于某种原因,它只适用于我的do + end
  • 您对牙套的看法是完全正确的。您不能在方法调用上省略括号并附加块。您必须使用 do end 作为块或包含括号。我已经相应地更新了答案。
  • 就 rspec "style" 资源而言,恐怕我没有答案,尽管我觉得我应该可以评论一下。如果我决定研究一下,我会在以后在这里添加评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-12
  • 2016-06-30
  • 2012-11-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多