【问题标题】:Rspec method is being called 2X, but can't find second timeRspec 方法被调用 2X,但第二次找不到
【发布时间】:2016-02-19 01:12:22
【问题描述】:

这是我的控制器规格

before do
    @order = Order.new
end
it "should call find & assign_attributes & test delivery_start methods" do
    Order.should_receive(:find).with("1").and_return(@order)
    Order.any_instance.should_receive(:assign_attributes).with({"id"=>"1", "cancel_reason" => "random"}).and_return(@order)
    Order.any_instance.should_receive(:delivery_start).and_return(Time.now)
    post :cancel, order: {id:1, cancel_reason:"random"}
end

失败是这样的:

Failure/Error: Unable to find matching line from backtrace
   (#<Order:0x007fdcb03836e8>).delivery_start(any args)
       expected: 1 time with any arguments
       received: 2 times with any arguments
 # this backtrace line is ignored

但我不确定为什么 delivery_start 基于此控制器操作被调用两次:

def cancel
    @order = Order.find(cancel_params[:id])
    @order.assign_attributes(cancel_params)
    if (@order.delivery_start - Time.now) > 24.hours
        if refund
            @order.save
            flash[:success] = "Your order has been successfully cancelled & refunded"
            redirect_to root_path
        else
            flash[:danger] = "Sorry we could not process your cancellation, please try again"
            render nothing: true
        end
    else
        @order.save
        flash[:success] = "Your order has been successfully cancelled"
        redirect_to root_path
    end
end

【问题讨论】:

  • 对不起,但它“应该调用 find & assign_attributes & test delivery_start 方法”做 Order.should_receive(:find).with("1").and_return(@order) Order.any_instance.should_receive(: assign_attributes).with({"id"=>"1", "cancel_reason" => "random"}).and_return(@order) Order.any_instance.should_receive(:delivery_start).and_return(Time.now) post :cancel , order: {id:1, cancel_reason:"random"} end
  • 我不确定,但我猜delivery_start 可能会显示在正在显示的视图中?这将是我对第二个“呼叫”来自哪里的猜测。
  • @TarynEast 没有调用delivery_start的关联视图
  • 值得一试:)

标签: ruby-on-rails ruby-on-rails-4 rspec controller rspec-rails


【解决方案1】:

我建议您测试行为而不是实现。虽然在某些情况下,您希望在控制器规范中对数据库进行存根并不是一个好主意,因为您正在测试控制器和模型层之间的集成。

此外,您的测试只是真正测试您的控制器如何完成工作,而不是实际完成。

describe SomeController, type: :controller do

  let(:order){ Order.create } # use let not ivars.

  describe '#cancel' do

    let(:valid_params) do
      { order: {id: '123', cancel_reason: "random"} }
    end

    context 'when refundable' do
      before { post :cancel, params }
      it 'cancels the order' do
        expect(order.reload.cancel_reason).to eq "random"
        # although you should have a model method so you can do this:
        # expect(order.cancelled?).to be_truthy
      end

      it 'redirects and notifies the user' do
         expect(response).to redirect_to root_path
         expect(flash[:success]).to eq 'Your order has been successfully cancelled & refunded'
      end
    end
  end
end

【讨论】:

  • Max,这是一个公平的评论,但在这种情况下,测试是这样设置的。还有其他规范正在检查控制器的方法是否按预期方式工作
  • 是吗?为什么要问你是否不想修复它?但是,嘿,它是你的应用程序。
  • 嗯...我的问题不是如何改变测试的性质,而是为什么特定规范可能没有通过
  • 有时修复错误的最佳方法...首先找到一种完全不同的更好的方法:D
【解决方案2】:

我会建议更多的期望,并根据您的使用情况返回 true 或 false。考虑以下更改

class SomeController < ApplicationController
  def cancel
    ...
    if refundable?
      ...
    end
  end

  private

  def refundable?
    (@order.delivery_start - Time.now) > 24.hours
  end
end

# spec/controllers/some_controller_spec.rb
describe SomeController, type: :controller do
  describe '#cancel' do
    context 'when refundable' do
      it 'cancels and refunds order' do
        order = double(:order)
        params = order: {id: '123', cancel_reason: "random"}
        expect(Order).to receive(:find).with('123').and_return(order)
        expect(order).to receive(:assign_attributes).with(params[:order]).and_return(order)
        expect(controller).to receive(:refundable?).and_return(true)
        expect(controller).to receive(:refund).and_return(true)
        expect(order).to receive(:save).and_return(true)
        post :cancel, params
        expect(response).to redirect_to '/your_root_path'
        expect(session[:flash]['flashes']).to eq({'success'=>'Your order has been successfully cancelled & refunded'})
        expect(assigns(:order)).to eq order
      end
    end
  end
end

【讨论】:

    【解决方案3】:

    对不起,这是一个非常不满意的答案,但是我重新启动了我的计算机并且规范通过了......

    以前对我来说很麻烦的一件事是我忘记保存代码,即运行测试的旧版本代码调用delivery_start 两次。但在这种情况下,我肯定检查过我已经保存了。我不知道为什么重新启动会修复它...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-05
      • 1970-01-01
      • 2017-06-07
      • 1970-01-01
      • 1970-01-01
      • 2015-03-17
      相关资源
      最近更新 更多