简体   繁体   中英

Rspec fails for Name has already been taken

I'm trying to make rspec testcases. But, Rspec fails for Name has already been taken.

It seems "let" evalulated each time "product" called.

How can I fix it?

Console

./spec/models/spree/product_decorator_spec.rb:31:in `block (4 levels) in <top (required)>'

ActiveRecord::RecordInvalid: Validation failed: Name has already been taken
./spec/models/spree/product_decorator_spec.rb:6:in `block (3 levels) in <top (required)>'
./spec/models/spree/product_decorator_spec.rb:20:in `block (4 levels) in <top (required)>'
./spec/models/spree/product_decorator_spec.rb:23:in `block (4 levels) in <top (required)>'

ActiveRecord::RecordInvalid: Validation failed: Name has already been taken
./spec/models/spree/product_decorator_spec.rb:6:in `block (3 levels) in <top (required)>'
./spec/models/spree/product_decorator_spec.rb:12:in `block (4 levels) in <top (required)>'
./spec/models/spree/product_decorator_spec.rb:15:in `block (4 levels) in <top (required)>'

product_decorator_spec.rb

require 'spec_helper'

describe Spree::Product do

  context '#create' do
    let(:us) { create(:zone, name: "US") }
    let(:china) { create(:zone, name: "China") }
    let(:japan) { create(:zone, name: "Japan") }


    context "when a product has no ng zone" do
      let(:product) { create(:product, zones: [us, china, japan]) }

      it "should get ng_zones correctly" do
        product.ng_zones.should match_array []
      end
    end

    context "when a product has one ng zone" do
      let(:product) { create(:product, zones: [us, china]) }

      it "should get ng_zones correctly" do
        product.ng_zones.should match_array ["Japan"]
      end
    end

    context "when a product has two ng zone" do
      let(:product) { create(:product, zones: [us]) }

      it "should get ng_zones correctly" do
        product.ng_zones.should match_array ["China", "Japan"]
      end
    end
  end
end

The body of the let is evaluated with every it block. I'm assuming you have a uniqueness constraint on your Zone classes.

You have 2 possibilities

  • Either build the variables in a before(:all) block and assign them to something like @us
  • Clean up your database after(:each)

You are testing the Product#create so, you won't need to really create zones for this particular test.

Instead you could just use build_stubbed method.

let(:us) { build_stubbed(:zone, name: "US") }
let(:china) { build_stubbed(:zone, name: "China") }
let(:japan) { build_stubbed(:zone, name: "Japan") }

This way, it's creation process are not going to rely on the database and also the validations for the Zone model and you have an awesome performance boost since you are not hitting the db for for each single test.

You can read about build_stubbed here .

Please let me know if it helps you somehow. ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM