为什么rspec说用should_receive没有收到这个方法?

时间:2012-10-10 01:50:45

标签: ruby ruby-on-rails-3 rspec2 rspec-rails

我的问题是,为什么我收到以下rspec错误消息? (下面的代码)我在StripeSubscription模型上创建了:update_payment方法。我已经在这里待了几个小时而且很困惑。

Failure/Error: @stripe_msub.should_receive(:update_payment).and_return(@stripe_msub)
       (#<StripeSubscription:0xb879154>).update_payment(any args)
           expected: 1 time
           received: 0 times



 ###Rspec test###
    describe "PUT 'update'" do
        context "signed-in teacher" do
           before(:each) do
            @teacher = Factory(:teacher)
            @teacher_upload = Factory(:teacher_upload,:teacher_id=>@teacher.id)
            @stripe_mplan = Factory(:stripe_plan)
            @new_stripe_card_token = 528
            @stripe_msub = Factory(:stripe_subscription,:teacher_id=>@teacher.id,:stripe_plan_id=>@stripe_mplan.id, :email=>@teacher.email,:account_status=>Acemt::Application::STRIPE_SUBSCRIPTION_ACCOUNT_STATUS[:active])
            @stripe_msub.stub!(:update_payment).and_return(@stripe_msub)
            StripeSubscription.stub!(:update_payment).and_return(@stripe_msub)
            StripeSubscription.stub!(:update_attributes).and_return(true)
            @stripe_customer = mock('Stripe::Customer')
            Stripe::Customer.stub!(:retrieve).with(@stripe_msub.stripe_customer_token).and_return(@stripe_customer)
            @stripe_customer.stub(:card=).and_return(true)
            @stripe_customer.stub(:save).and_return(true)
            test_sign_in(@teacher)
          end
          it "should update credit card information" do
            @stripe_msub.should_receive(:update_payment)
            Stripe::Customer.should_receive(:retrieve).with(@stripe_msub.stripe_customer_token).and_return(@stripe_customer)
            @stripe_customer.should_receive(:card=)
            @stripe_customer.should_receive(:save).and_return(@stripe_customer)

            put :update, :teacher_id=>@teacher.id, :stripe_subscription=>{:stripe_plan_id=>@stripe_msub.stripe_plan_id, :teacher_id=>@stripe_msub.teacher_id, :email=>@stripe_msub.email, :stripe_customer_token=>@stripe_msub.stripe_customer_token,:stripe_card_token=>@new_stripe_card_token,:account_status=>@stripe_msub.account_status}
            @teacher.stripe_subscription.should == @stripe_msub
            response.should redirect_to teacher_path(@teacher)

          end
        end #signed in teacher
      end #PUT update

###controller###
class StripeSubscriptionsController < ApplicationController
  before_filter :signed_in_teacher
  before_filter :correct_teacher
  :
   def update
    #@stripe_subscription = StripeSubscription.find_by_id(params[:id])
    @stripe_subscription = @teacher.stripe_subscription
    if @stripe_subscription.update_payment(params[:stripe_subscription])
      #handle successful update
      flash[:success] = "Credit card updated"
      sign_in @teacher
      redirect_to @teacher
    else
      render 'edit'
    end
  end
  :
end

###model###
class StripeSubscription < ActiveRecord::Base
  #attr_accessible :email, :plan_id, :stripe_customer_token, :teacher_id, :account_status
  validates_presence_of :stripe_plan_id
  validates_presence_of :email
  validates_presence_of :teacher_id

  belongs_to :stripe_plan, :class_name=>"StripePlan"
  belongs_to :teacher
  attr_accessor :stripe_card_token

  def save_with_payment
    if valid?
      customer = Stripe::Customer.create(description: email, plan: stripe_plan_id, card: stripe_card_token)
      self.stripe_customer_token = customer.id
      save!
    end

    rescue Stripe::InvalidRequestError => e
      logger.error "Stripe error while creating customer: #{e.message}"
      errors.add :base, "There was a problem with your credit card."

  end
  def update_payment(stripe_params)
    if valid?
      customer = Stripe::Customer.retrieve(self.stripe_customer_token)
      customer.card = stripe_params[:stripe_card_token]
      status = customer.save #update card info on Stripe
      update_attributes(stripe_params) #save StripeSubscription object
    end

    rescue Stripe::InvalidRequestError => e
      logger.error "Stripe error while updating your credit card: #{e.message}"
      errors.add :base, "There was a problem with your credit card."
  end
end

1 个答案:

答案 0 :(得分:0)

您正在为规范(@stripe_msub)中的对象设置期望值。但是,在控制器中,您可能从数据库加载教师并获得其订阅(@stripe_subscription)。

由于通过数据库的往返,此对象与您设置的期望对象不同,因此您设置预期的对象(规范中的@stripe_msub)从未接收到方法调用因此rspec抱怨。

要解决此问题,您必须将所有数据库调用存根,并确保您的规范中的对象出现在控制器中。我不知道控制器中确切地设置了@teacher(我想在其中一个过滤器中)所以我不能给你确切的解决方案,但它会是这样的:

# I assume this is the implentation of your filter in the controller
def signed_in_teacher
  @teacher = Teacher.find_by_id(params[:teacher_id])
end

# Then you would have to add the following mocks/stubs to your spec
Teacher.should_receive(:find_by_id).once.with(@teacher.id).and_return(@teacher)