【问题标题】:Correct way of stubbing method call in RSpec requestRSpec请求中存根方法调用的正确方法
【发布时间】:2018-09-15 10:52:49
【问题描述】:

我试图在我的请求规范中删除 :authenticate_user 方法调用,以便测试用户的关联创建。我使用这些博客文章作为存根指南:

1)https://8thlight.com/blog/mike-knepper/2014/07/01/stubbing-authentication-and-authorization-in-controller-specs.html

2)http://johnnyji.me/rspec/2015/06/18/stubbing-controller-instance-methods-in-rspec.html

我在存根方面没有取得任何成功,我无法弄清楚我错过了什么。

当我尝试时

it 'creates a new contract' do
      allow(controller).to receive(:authenticate_user).and_return(user)
      post api_v1_user_contracts_path(user), { params: contract_params}
      expect(response).to have_http_status(200)
    end

我得到:

当我尝试时:

it 'creates a new contract' do
      allow_any_instance_of(controller).to receive(:authenticate_user).and_return(user)
      post api_v1_user_contracts_path(user), { params: contract_params}
      expect(response).to have_http_status(200)
    end

我收到了

我的代码: 规范/请求/contracts_api_spec.rb

require 'rails_helper'
require 'pry'
context "POST #create" do
    let (:user) { User.create(full_name: "Jason Bourne", email: "jbourne@test.com", password: "123456") }
    let (:contract_params) do
      {
        "contract[vendor]" => "Lebara",
        "contract[starts_on]" => "2018-12-12",
        "contract[ends_on]" => "2018-12-16",
        "contract[price]" => "15"
      }
    end

    it 'creates a new contract' do
      allow(controller).to receive(:authenticate_user).and_return(user)

      post api_v1_user_contracts_path(user), { params: contract_params}
      expect(response).to have_http_status(200)
    end

app/controllers/api/v1/contracts_controller.rb

class Api::V1::ContractsController < ApplicationController
  before_action :authenticate_user

  def show
    if @current_user.contracts.find_by(id: params[:id])
      render json: @current_user.contracts.find_by(id: params[:id])
    else
      render json: { error: "Contract not found"}, status: 400
    end
  end

  def create
    contract = @current_user.contracts.build(contract_params)
    if contract.save
      render json: contract
    else
      render json: { error: contract.errors }, status: 400
    end
  end

app/controllers/concerns/token_authenticable.rb

class NotAuthorizedException < StandardError; end

module TokenAuthenticatable
  extend ActiveSupport::Concern

  included do
    attr_reader :current_user

    before_action :authenticate_user

    rescue_from NotAuthorizedException, with: -> { render json: { error: 'Not Authorized' }, status: :unauthorized }
  end

  private

  def authenticate_user
    @current_user = DecodeAuthenticationCommand.call(request.headers).result
    raise NotAuthorizedException unless @current_user
  end
end

其他问题:

1) 我应该使用真正的 User 对象,还是应该是双精度对象?我假设它应该是真实用户,以便测试关联创建是否正常。

2) 我应该使用 allow(Api::V1::ContractsController).to receive(:authenticate_user).and_return(user) 吗?我以前尝试过但没有用,但我不知道这是因为其他东西也破坏了它。

感谢您提供的任何反馈!

【问题讨论】:

  • 我刚试过,它有效,谢谢:)。我想我不能为用户使用测试替身,否则这个测试就没有意义了?
  • 我已将评论移至答案,对其他人会更好。

标签: ruby-on-rails rspec stubbing


【解决方案1】:

关键是authenticate_user 将 user 分配给变量(您稍后会使用它)。请尝试:

allow(DecodeAuthenticationCommand).to receive_message_chain(:call, :result).and_return(user)

使用测试替身,您必须为用户定义所有方法,例如contracts。此外,您正在检查合同是否已创建 - 在我看来,为 user 使用真实对象是完全可以的。

【讨论】:

  • 谢谢,我不确定什么时候适合使用真实的物体,但您已将其清理干净。
  • 为什么不允许(Api::V1::ContractsController).to receive(:authenticate_user).and_return(user) 或allow(controller).to .. 在这种情况下工作?跨度>
  • authenticate_user 将user 分配给@current_user。稍后,在您的代码中,您使用@current_user。我认为您的代码会引发错误,因为@current_user 将为零(contract = nil.contracts.build(contract_params))
  • 另外authenticate_user 实际上并不返回user。成功后将返回nil。所以and_return 具有误导性。
  • @Derek 抱歉,我不明白为什么如果成功它实际上不会返回用户?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-08-05
  • 1970-01-01
  • 1970-01-01
  • 2015-07-23
  • 1970-01-01
  • 1970-01-01
  • 2012-02-21
相关资源
最近更新 更多