我可以在 RSpec 中写一个期望,要求使用特定参数仅调用一次方法吗?

问题描述 投票:0回答:1

我刚刚完成第一年在 Rails 中编写生产代码的工作,我并没有真正被困在这里,但我所经历的非 ruby 性很奇怪,我想看看是否有人遇到这个问题。

假设您正在编写涉及外部 API 的代码,因此您对该 API 的调用需要精心设计。为了确保这些调用正确发生,我想编写一些规范,要求这些调用仅发生一定次数并带有特定参数。像这样的东西:

it "only calls the wrapper once with the correct arguments" do
  expect(Wrapper).to have_received(:do_magic).once
  expect(Wrapper).to have_received(:do_magic).with(flowers_in_sleeve: false)
end

但是有两个期望是不好的做法!我使用 RuboCop 来检查(我喜欢遵守它的约定),所以我有两个选择:要么将其分解为两个期望,要么禁用在一个块中具有多个期望的规则。

所以,这并不是一个完全惊天动地的问题。但我觉得很奇怪,RSpec 没有更方便的方法来满足这种情况。也许我只需要忍住并写下两个期望。我的目标是如果可能的话,在一个期望中做到这一点。

这是我想到的主要解决方案:

it "only calls the wrapper once with the correct arguments" do
  expect(Wrapper).to have_received(:do_magic).once.with(flowers_in_sleeve: false)
end

但是,只要您使用这些参数至少调用该方法一次,就允许对包装器进行多次调用。真的,如果你看看你写的句子:

I expect wrapper to be called once with flowers in sleeve to be false

这种行为是有道理的,因为我不是说:

I expect wrapper to be called only once with flower in sleeve to be false
.

ruby-on-rails ruby rspec tdd
1个回答
0
投票

正如 @max 评论的那样,有多重期望并不一定是不好的做法。 多个

expect
语句完全有可能有助于覆盖一种行为。当您有令人信服的理由时,您可以自由修改 RuboCop 默认值。

话虽如此,您可以使用以下策略来编写规范,要求调用仅发生一定次数并带有特定参数。您可以捕获传递给每次调用

do_magic
的所有参数,然后针对参数集捕获
expect

# lib/magic_performer.rb
class Wrapper
  def self.do_magic(options = {})
    # implementation goes here
  end
end

class MagicPerformer
  def perform_magic
    Wrapper.do_magic(flowers_in_sleeve: false)
  end
end
# spec/magic_performer_spec.rb
require 'rspec'
require_relative '../lib/magic_performer'

RSpec.describe MagicPerformer do
  let(:args_in_calls_to_do_magic) { [] }

  before do
    allow(Wrapper).to receive(:do_magic) do |*args, **kwargs|
      args_in_calls_to_do_magic << [args, kwargs]
    end

    MagicPerformer.new.perform_magic
  end

  it 'only calls the wrapper once with the correct arguments' do
    expect(args_in_calls_to_do_magic)
      .to eq([
               [[], { flowers_in_sleeve: false }]
             ])
  end
end

另外,考虑这种类型的测试是“白盒”测试(与“黑盒”测试相对)。这样的测试了解被测类

Wrapper
的实现细节。一般来说,最好编写一个知道任何此类实现细节的测试,例如
Wrapper
内部调用
MagicPerformer
。黑盒测试使您能够在将来重构被测类,例如删除其对
MagicPerformer
的依赖,而无需更改测试。考虑是否可以重写测试,使其仅针对
Wrapper
的可观察行为进行预期。

© www.soinside.com 2019 - 2024. All rights reserved.