2016-04-12 91 views
1

私はrspec + factory_girlを持つrails4アプリを持っています。製品に少なくとも1つの機能、競争、用途、業界があることを確認する検証をテストしたいと思います。最初の3つは製品に属していなければなりませんが、業界はそれ自体で存在することができます。私は最初の3つの作業をすることさえできないので、業界をテストに入れようとしていません。rspec + factoryモデルでネストされた属性をテストする

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

ない完全な答えを行うのに十分な高機能: 'product.product_features <<:あなたがcreate_listを行う必要はありません、あなたのような何かを行うことができます'' create(:product_feature、product:product) 'いくつかの数が必要な場合は' xx {} 'ブロックを囲みます。 –

+0

ジム、十分に機能していないのはどういう意味ですか?その場合になぜ動作するのか、なぜこのコードで動作しないのか教えてください。 –

+0

通常、APIドキュメントへの参照で回答をバックアップします。この場合、私はそれが「素早く汚れている」と感じました –

答えて

1

あなたのテストをしましょう宝石shouldahttps://github.com/thoughtbot/shoulda)がありますaccepts_nested_attributes_for(検証と関連付けも)を1つのマッチャーで直接実行できます。 (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 
+0

Sibevin、入れ子のattrsで 'shoulda-matchers'を使用しています。モデルに 'accepts_nested_attributes_for'が設定されているかどうかテストするだけではありませんか?このコードでは、作成した製品に少なくとも1つの 'product_feature'、' product_usecase'などがあるかどうかをテストします。バリデータで 'product.rb'を更新しました。 –

+0

Sibevin、plsも私の前のコメントをチェックします。だから私はこのコードを使い、 'ActiveRecord :: AssociationTypeMismatch:ProductFeature(#70333990300640)が期待され、ハッシュを取得しました(#70333940263240)'というエラーを出しました。だから私はまだ作成されていない製品は 'attributes_for(:product_feature、product:#この製品)'に渡されるべきだと思いますが、ヒントはありません。私は一度に作り出さなければならないので、鶏卵の問題のように感じます。だから私は最初に製品を作成しようとすると、少なくとも1つの機能を取得する必要がありますエラーを作成し、機能を作成しようとすると、製品を取得するエラーを定義する必要があります。 –

+0

@SzilardMagyarあなたの最初のコメントは正しいので、実装ではなく動作をテストする方が好きです。 (shouldaは同様の方法でmatcherを実装していますが)。 –

関連する問題