我有一个带有rspec + factory_girl的rails4应用程序。我想测试验证,确保产品至少有一个功能,竞争,用例和行业。前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
答案 0 :(得分:1)
有一个gem shoulda
(https://github.com/thoughtbot/shoulda),可让您直接使用一个匹配器测试accepts_nested_attributes_for
(验证和关联)。但是如果你更喜欢测试行为(什么)而不是实现(如何),你可以做类似下面的事情......
就像我之前提到的那样(setting up objects for model testing with 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