Solidus:在after_save回调中执行的代码在rspec中返回错误

时间:2017-08-05 21:11:43

标签: ruby-on-rails rspec solidus

我使用最新版本的Solidus电子商务(Spree的分支),我遇到了这个问题。快速描述:

  1. 在管理员中我创建Spree ::会员记录
  2. Spree中的after_save回调::成员资格创建产品和2个变种
  3. 此代码在我运行服务器时有效,但是当我尝试使用Rspec时,它会给我这个错误:

    Failure/Error: reload.product.setup_membership_variants
    
     NoMethodError:
       undefined method `setup_membership_variants' for nil:NilClass
     # ./app/models/spree/membership.rb:26:in `block in setup_product'
     # ./app/models/spree/membership.rb:18:in `setup_product'
     # /box/gems/factory_girl-4.8.0/lib/factory_girl/configuration.rb:18:in `block in initialize'
     # /box/gems/factory_girl-4.8.0/lib/factory_girl/evaluation.rb:15:in `create'
     # /box/gems/factory_girl-4.8.0/lib/factory_girl/strategy/create.rb:12:in `block in result'
     # /box/gems/factory_girl-4.8.0/lib/factory_girl/strategy/create.rb:9:in `tap'
     # /box/gems/factory_girl-4.8.0/lib/factory_girl/strategy/create.rb:9:in `result'
     # /box/gems/factory_girl-4.8.0/lib/factory_girl/factory.rb:42:in `run'
     # /box/gems/factory_girl-4.8.0/lib/factory_girl/factory_runner.rb:29:in `block in run'
     # /box/gems/factory_girl-4.8.0/lib/factory_girl/factory_runner.rb:28:in `run'
     # /box/gems/factory_girl-4.8.0/lib/factory_girl/strategy_syntax_method_registrar.rb:20:in `block in define_singular_strategy_method'
     # ./spec/controllers/spree/premium_controller_spec.rb:4:in `block (2 levels) in <top (required)>'
     # ./spec/controllers/spree/premium_controller_spec.rb:33:in `block (6 levels) in <top (required)>'
     # ./spec/controllers/spree/premium_controller_spec.rb:53:in `block (8 levels) in <top (required)>'
     # ./spec/controllers/spree/premium_controller_spec.rb:53:in `block (7 levels) in <top (required)>'
    

    以下是我使用的代码:

      

    membership.rb

    class Spree::Membership < Spree::Base
    
      has_many :active_memberships, class_name: 'Spree::ActiveMembership', dependent: :destroy
    
      has_one :membership_product, class_name: "Spree::MembershipProduct", dependent: :destroy
      has_one :product, through: :membership_product, source: :product
    
      validates :name, presence: true
      validates :monthly_quota, presence: true
      validates :price, presence: true
    
      after_save :setup_product
    
      private
    
      def setup_product
        if product.nil?
          ActiveRecord::Base.transaction do
            create_membership_product(
              product: Spree::Product.create(
                name: name, 
                price: price, 
                shipping_category: Spree::ShippingCategory.find_by(name: "Default")
              )
            )
            reload.product.setup_membership_variants
          end
        else
          product.update(name: name, price: price)
        end
      end
    
    end
    
      

    product_decorator.rb

    Spree::Product.class_eval do
      def setup_membership_variants
        ot = Spree::OptionType.find_or_create_by(name: "Membership")
        option_types << ot
    
        if ot.option_values.empty?
          ["Monthly", "Yearly"].each do |freq|
            ot.option_values.create(name: freq, presentation: freq)
          end
        end
    
    
        month = variants.create(is_master: false, price: price, track_inventory: false)
        month.option_values << Spree::OptionValue.find_by(name: "Monthly")
        year = variants.create(is_master: false, price: price * 12, track_inventory: false)
    year.option_values << Spree::OptionValue.find_by(name: "Yearly")
      end
    end
    
      

    membership .rb工厂

    FactoryGirl.define do
      factory :membership, class: Spree::Membership do
        name   {FFaker::Lorem.word}
        monthly_quota { rand(10..200) }
        price { rand(10..200) }
    
        trait :unnamed do
          name   nil
        end
    
        trait :without_quota do
          monthly_quota nil
        end
    
        trait :priceless do
          price nil
        end
      end
    end
    
      

    控制器测试的例子

    require 'rails_helper'
    
    RSpec.describe Spree::PremiumController, type: :controller do
      let(:valid_membership) { create(:membership) }
      let(:variant) { create(:master_variant) }
    
      context "#show" do
        it "returns http success" do
          get :show
          expect(response).to have_http_status(:success)
        end
        it "returns all memberships" do 
          get :show
          expect(assigns[:memberships]).to include(valid_membership)
        end
      end
    
      context "#create" do 
        let!(:store) { create(:store) }
    
        context "user not logged" do 
    
          context "valid attributes" do
            context "user doesn't exist in database" do
              subject do
                post(:create, params: { 
                  premium: { 
                    first_name: "Ondrej", 
                    last_name: "Kubala", 
                    email: "ondrej@bala.com", 
                    password: "test123",
                    password_confirmation: "test123",
                    membership_id: valid_membership.id, 
                    payment_frequency: "1", #monthly yearly is 2 
                    cc_number: "4111111111111111", 
                    cc_exp_date: "10/22", 
                    cvv: "123"
                  }
                }) 
              end
    
              it "creates user with valid attributes" do 
                expect { subject }.to change { Spree::User.count }.from(0).to(1)
              end
    
              it "logs in user" do 
                expect(controller.warden).to receive(:set_user)
                subject
              end
    
              context "create order with variant" do
                it "should handle population" do 
                  expect { subject }.to change { Spree::Order.count }.by(1)
                  user = Spree::User.find_by email: "ondrej@bala.com"
    
                  order = user.orders.last
                  expect(response).to redirect_to go_premium_path
    
                  expect(order.line_items.size).to eq(1)
                  # line_item = order.line_items.first
                  # expect(line_item.variant_id).to eq(valid_membership.reload.product.variants.)
                end
                it "charges credit card"
                it "should redirect to account page"
              end
            end
    
            context "user already exists"
          end
    
          context "wrong user attributes" do
    
          end
    
          context "wrong payment attributes" do 
    
          end
        end
    
        context "user is logged in" do 
          let(:user) { create(:user) }
    
          before do
            allow(controller).to receive_messages try_spree_current_user: user
            allow(controller).to receive_messages spree_current_user: user
          end
    
          it "doesn't create user"
        end
      end
    end
    

    我在Rspec上没有太多的经验,但是当服务器在开发中运行时,它很有效,但在测试中它给了我这个错误。

    知道出了什么问题吗?

1 个答案:

答案 0 :(得分:0)

我的猜测是产品创建调用由于某种原因失败了。 尝试bang版本(product: Spree::Product.create!)以便在发生时抛出错误。

如果确实创建了产品,请使用prybyebug来确定reload成员资格后产品与membership无关的原因。