2016-04-12 25 views
1

rspec + factory_girl ile bir rails4 uygulaması var. Ürünün en az bir özellik, rekabet, kullanım alanı ve endüstriye sahip olmasını sağlayan doğrulamayı test etmek istiyorum. İlk 3 ürüne ait olmalı, ancak endüstri kendi başına var olabilir. İlk 3'te iş yapamayacağım için henüz endüstriyi test etmeye çalışmıyorum.rspec + fabrika modeli test iç içe öznitelikleri

Ürün_dosyası, product_competition ve product_usecase içeren bir ürün fabrikası oluşturduğum yaklaşımı denedim. Bazı sebeplerden dolayı çalışmıyor.

Doğru yaklaşımı kullanır mıyım? Öyleyse, kodumdaki sorun nedir?

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 

fabrika (GÜNCELLENDİ)

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 

test edelim bir gem shoulda (https://github.com/thoughtbot/shoulda) bulunmaktadır 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

Değil: 'product.product_features <<: Eğer böyle bir şey yapabilirsiniz, bir create_list yapmak gerekmez yaratın (: product_feature, product: product) '' x.times {} 'bir miktarına ihtiyaç duyarsanız etrafını sarın. –

+0

Jim, ne kadar yetenekli değil, ne demek istiyorsun? Bana bu durumda neden işe yarayacağını ve neden bu kodla burada çalışmadığını söyler misiniz? –

+0

Genellikle yanıtlarımı API belgelerine referanslarla yedekliyorum. Bu durumda, 'hızlı ve kirli' –

cevap

1

accepts_nested_attributes_for (doğrulamalar ve birlikler) doğrudan tek bir eşleştirici ile. Ancak, davranışı (hangisini) daha çok uygulamayı (nasıl) test etmeyi tercih ederseniz, aşağıdaki gibi bir şey yapabilirsiniz ...

Daha önce bahsettiğim gibi (setting up objects for model testing with factory_girl), ilk önce fabrikalardan dernekleri kaldırırım.

Fabrikalar

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 

Özellikleri

tam bir cevap yapmak için yeterli featureful
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 
+0

Sibevin, 'shoulda-matchers' iç içe attrs ile kullanıyorum hissettim. Modelde 'accepts_nested_attributes_for' ayarlanmış olup olmadığını test etmek değil mi? Bu kodla, oluşturulan ürünün en az bir tane "product_feature", "product_usecase", vb. Olup olmadığını test etmeye çalışıyorum. "Product.rb" yi validator ile güncelledim. –

+0

Sibevin, pls ayrıca ön yorumumu kontrol et. Bu yüzden bu kodla oynadım ve ActiveRecord :: AssociationTypeMismatch: ProductFeature (# 70333990300640) bekleniyor, Hash (# 70333940263240) 'hatasını aldım. Öyleyse, henüz yaratılmamış olan ürünün "attributes_for (: product_feature, product: #this product") ürününe aktarıldığını tahmin ediyorum. Bir kerede yaratılmak zorunda oldukları için tavuk yumurtası problemi gibi hissediyorum. Yani önce ürün oluşturmaya çalışırsam, en az 1 özellik elde etmem gerekiyorsa hata yaratılmalı ve eğer bu özelliği yaratmaya çalışırsanız, ürün tanımlanırken hata tanımlanmalıdır. –

+0

@SzilardMagyar İlk yorumunuz doğru, bu yüzden uygulamayı değil, davranışları test etmeyi tercih ediyorum. (Shoulda, eşleştiriciyi uygulamak için benzer bir yol kullanıyor olsa da). –

İlgili konular