rspec +工厂模型测试嵌套属性

我有一个带有rspec + factory_girl的rails4应用程序。 我想测试validation,确保产品至少有一个function,竞争,用例和行业。 前3个必须属于产品,但行业可以独立存在。 我还没有试过把工业放在测试中,因为我甚至不能把工作放在前3。

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

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

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(更新)

 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

 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 shouldahttps://github.com/thoughtbot/shoulda ),它允许您直接使用一个匹配器测试accepts_nested_attributes_for (validation和关联)。 但是如果您更喜欢测试行为(什么)而不是实现(如何),您可以执行以下操作…

就像我之前提到的那样( 使用factory_girl设置模型测试的对象 ),我会首先从工厂中删除关联。

工厂

 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