代码之家  ›  专栏  ›  技术社区  ›  Carl

Rspec抛出带有或不带参数的ArgumentError

  •  0
  • Carl  · 技术社区  · 5 年前

    app/services/application_service.rb

    class ApplicationService
      def self.call(*args, &block)
        new(*args, &block).call
      end
    end
    

    app/services/basic_objects/create_payment.rb

      module BasicObjects
        class CreatePayment < ApplicationService
          def initialize(args)
            @transaction_id = args[:transaction_id]
          end
    
          def call
            transaction = Transaction.find(@transaction_id)
            payment = Payment.new(transaction: transaction)
            payment.save
          rescue CustomError => e
            if /waiting/i === e.message
              puts "Ignoring exception \"#{e.message}\" to prevent retry"
            else
              raise e
            end
          end
        end
    

    这是测试

    describe BasicObjects::CreatePayment, type: :model do
      describe '#call' do
        let(:params) { { transaction_id: "xyz" } }
    
        context 'when there is a rescued error' do
          before do
            allow_any_instance_of(Payment)
              .to receive(:save)
              .and_raise(CustomError, "waiting")
          end
    
          it 'does not raise an error' do
             expect { described_class.call(params) }.not_to raise_error
          end
        end
      end
    end
    

    它的响应是这样的错误: expected no Exception, got #<ArgumentError: wrong number of arguments (given 1, expected 0)

    expect(described_class.call).not_to raise_error 我因未发送参数而出错

    <BasicObjects::CreatePayment (class)> received :call with unexpected arguments
             expected: ({:transaction_id=>"xyz"})
                  got: (no args)
    

    所以,我把它去掉 with(params)

    context 'when there is a rescued error' do
        before do
          allow(described_class).to receive(:call).and_raise(CustomError, "waiting")
        end
    
        it 'does not raise an error' do
           expect(described_class.call).not_to raise_error
        end
      end
    

    我得到

    ArgumentError:
           wrong number of arguments (given 1, expected 0)
    

    非常感谢您的帮助

    expected no Exception, got #<ArgumentError: wrong number of arguments (given 1, expected 0)>

    0 回复  |  直到 5 年前
        1
  •  1
  •   Cassandra S.    5 年前

    哇,这是一次令人困惑的旅程。好的,让我们回顾一下:

    当你写作时 allow(described_class).to receive(:call).and_raise(...) 你是这么说的 这 方法:

    class ApplicationService
      def self.call(*args, &block)
        new(*args, &block).call
      end
    end
    

    应该引起错误。在本地尝试代码时,实际情况就是这样。

    call 这不是正在测试的,我建议您这样测试:

    it 'does not raise an error' do
      dbl = class_double(Transaction)
      allow(dbl).to receive(:find).and_raise(CustomError, 'waiting')
      expect { described_class.new(params).call }.not_to raise_error
    end
    

    实际上,您不能存根实例方法的 ,因为这样做还将删除实际的 rescue 你正在测试的。

        2
  •  0
  •   Paul    5 年前

    好的,这里有一些事情在起作用,所以让我们一件一件地去。


    你的 create_payment.rb 定义一个实例方法 call CreatePayment . 另一方面,您的测试代码是模拟和调用 呼叫 described_class 所以,一个类方法。

    您可能希望创建的实例 在你的规格第一。

    CreatePayment.new(args).call
    

    按定义 创造支付 呼叫

    模拟不存在的方法时,会收到以下错误消息:

     Failure/Error: allow(described_class).to receive(:call).with(params).and_raise(CustomError, "waiting")
       SomeClass does not implement: call
    

    就是 不 发生了什么,请检查祖先:我通过添加一个类方法来重现错误 不接受祖先的任何参数:

    class SomeAncestor < Object
      def self.call
        raise "Abstract!"
      end
    end
    
    class SomeClass < SomeAncestor;
    end
    

    这会导致与您看到的相同的错误:

         Failure/Error: allow(described_class).to receive(:call).with(params).and_raise(CustomError, "waiting")
           Wrong number of arguments. Expected 0, got 1.
    

    ApplicationService 可能有一些抽象的实现 呼叫 类方法。

    这里的要点是“mock应该符合原始方法的签名”。但根本原因似乎仍然是类和实例方法之间的混淆,因此第一部分仍然有效 需要先实例化,然后调用。


    RSpec.describe Whatever do
      it 'does something' do
        ... described_class ...
      end
    end
    

    如果示例组的第一个参数是类,则该类为 通过 描述了\u class()方法。

    描述类 Whatever 在我上面的例子中。在你的规格中是 nil 无

    把事情搞砸了。我不能很精确地指出原因,但这种行为不会发生在普通对象上。这实际上是一个常见错误,因此您可能会看到RSpec发出的警告:

     WARNING: An expectation of `:call` was set on `nil`. To allow expectations on `nil` and suppress this message, set `RSpec::Mocks.configuration.allow_message_expectations_on_nil` to `true`. To disallow expectations on `nil`, set `RSpec::Mocks.configuration.allow_message_expectations_on_nil` to `false`. Called from .../spec/whatever.rb:10:in `block (3 levels) in <top (required)>'`.
    

    那么具体说明 呼吁 describe