rspec + 工厂模型测试嵌套属性 [英] rspec + factory model testing nested attributes

查看:20
本文介绍了rspec + 工厂模型测试嵌套属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有 rspec + factory_girl 的 rails4 应用程序.我想测试确保产品至少具有一项功能、竞争、用例和行业的验证.前 3 个必须属于产品,但行业可以独立存在.我还没有试过把工业放在测试中,因为我什至不能让工作成为前 3.

I have a rails4 app with rspec + factory_girl. I would like to test the validation that makes sure the product has at least one feature, competition, usecase and industry. The first 3 must belong to a product, but industry can exist on its own. I haven't tried to put industry in the test yet since I can't even make work the first 3.

我尝试了以下方法,在该方法中我创建了一个具有 product_feature、product_competition 和 product_usecase 的产品工厂.由于某种原因,它不起作用.

I tried the approach below in which I create a product factory that has product_feature, product_competition and product_usecase. For some reason it's not working.

我是否使用了正确的方法?如果是这样,我的代码有什么问题?

Do I use the right approach? If so, what's wrong with my code?

1) Product nested attribute validation has a valid factory
     Failure/Error: expect(create(:product_with_nested_attrs)).to be_valid

     ActiveRecord::RecordInvalid:
       Validation failed: You have to choose at least 1 industry., You must have at least 1 product feature., You must name at least 1 competition., You must describe at least 1 usecase.

product.rb(更新)

product.rb (UPDATED)

belongs_to :user
has_many :industry_products, dependent: :destroy, inverse_of: :product
has_many :industries, through: :industry_products #industry exists without product; connected with has_many thru association
has_many :product_features, dependent: :destroy
has_many :product_competitions, dependent: :destroy
has_many :product_usecases, dependent: :destroy

accepts_nested_attributes_for :industry_products, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :product_features, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :product_competitions, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :product_usecases, reject_if: :all_blank, allow_destroy: true

#UPDATE

validate :product_features_limit #Also have it for product_usecases and product_competititons

def product_features_limit
  if self.product_features.reject(&:marked_for_destruction?).count > 10
    self.errors.add :base, "You can't have more than 10 features."
  elsif self.product_features.reject(&:marked_for_destruction?).count < 1
    self.errors.add :base, "You must have at least 1 product feature."
  end
end

工厂

FactoryGirl.define do

  factory :product_competititon do
    competitor { Faker::Commerce.product_name }
    differentiator { Faker::Lorem.paragraph }
    product
  end

  factory :product_feature do
    feature { Faker::Lorem.paragraph }
    product
  end

  factory :product_usecase do
    example { Faker::Lorem.sentence }
    detail { Fakert::Lorem.paragraph }
    product
  end

  factory :product do
    name { Faker::Commerce.product_name }
    company { Faker::Company.name }
    website { 'https://example.com' }
    oneliner { Faker::Lorem.sentence }
    description { Faker::Lorem.paragraph }
    user

    factory :product_with_nested_attrs do
      transient do
        nested_attrs_count 1
      end
      after(:create) do |product, evaluator|
        create_list(:product_feature, evaluator.nested_attrs_count, product: product)
        create_list(:product_competititon, evaluator.nested_attrs_count, product: product)
        create_list(:product_usecase, evaluator.nested_attrs_count, product: product)
      end
    end
  end
end

product_spec.rb

product_spec.rb

RSpec.describe Product, type: :model do

  describe "nested attribute validation" do

    it "has a valid factory" do
      expect(create(:product_with_nested_attrs).to be_valid
    end

  end
end

推荐答案

有一个 gem shoulda (https://github.com/thoughtbot/shoulda),它让您可以直接使用一个匹配器测试 accepts_nested_attributes_for(验证和关联).但是,如果您更喜欢测试行为(什么)而不是实现(如何),您可以执行以下操作...

There is a gem shoulda (https://github.com/thoughtbot/shoulda) which let you test accepts_nested_attributes_for (validations and associations as well) directly with one single matcher. But if you prefer to test the behavior(what) rather then implementation(how), you can do something like follows ...

正如我之前提到的(使用 factory_girl 设置模型测试对象),我会从工厂中删除关联首先.

Just as what I mentioned before (setting up objects for model testing with factory_girl), I would remove associations from factories first.

工厂

factory :product_competititon do
  competitor { Faker::Commerce.product_name }
  differentiator { Faker::Lorem.paragraph }
end

factory :product_feature do
  feature { Faker::Lorem.paragraph }
end

factory :product_usecase do
  example { Faker::Lorem.sentence }
  detail { Fakert::Lorem.paragraph }
end

factory :product do
  name { Faker::Commerce.product_name }
  company { Faker::Company.name }
  website { 'https://example.com' }
  oneliner { Faker::Lorem.sentence }
  description { Faker::Lorem.paragraph }
end

规格

RSpec.describe Product, type: :model do

  describe "validation" do
    let(:user) { create(:user) }

    it "should be valid if a product has at least one competition, feature, usecase and industry" do
      attr = attributes_for(:project).merge({
        user_id: user.id,
        product_competitions: [attributes_for(:project_competition)],
        product_features: [attributes_for(:project_feature)],
        product_usecases: [attributes_for(:project_usecase)],
        product_industries: [attributes_for(:industry)],
      })
      expect(Product.new(attr)).to be_valid
    end

    it "should be invalid if no competition is given" do
      attr = attributes_for(:project).merge({
        user_id: user.id,
        product_features: [attributes_for(:project_feature)],
        product_usecases: [attributes_for(:project_usecase)],
        product_industries: [attributes_for(:industry)],
      })
      expect(Product.new(attr)).to be_invalid
    end

    it "should be invalid if no feature is given" do
      attr = attributes_for(:project).merge({
        user_id: user.id,
        product_competitions: [attributes_for(:project_competition)],
        product_usecases: [attributes_for(:project_usecase)],
        product_industries: [attributes_for(:industry)],
      })
      expect(Product.new(attr)).to be_invalid
    end

    # ... similar test cases for usecase and industry validation ...

  end
end

这篇关于rspec + 工厂模型测试嵌套属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆