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

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

问题描述

我有一个带有rspec + factory_girl的rails4应用程序.我想测试验证,以确保产品至少具有一项功能,竞争,用例和行业.前三个必须属于产品,但是行业可以独立存在.自从我什至无法使第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

推荐答案

有一个宝石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天全站免登陆