在自定义匹配器中使用内置匹配器中的rspec

时间:2017-09-08 13:41:19

标签: ruby rspec

我有一个测试套件,有太多这样的断言

expect(array_1).to match_array array_2
expect(array_3).to match_array array_4
expect(array_5).to match_array array_5

等等。

我希望将这些检查包装在自定义匹配器中,但在该自定义匹配器中,我希望使用match_array匹配器,因为我真的很喜欢它返回的错误消息,列出了缺失和额外元素的情况。不匹配。

这样的事情:

RSpec::Matchers.define :have_data do |data|
  match do |actual|
    actual.eql? data # I don't want to do this.
    actual.match_array? data # <<- I'd like do do something like this to retain the matcher behaviour
  end
end

我能做到这一点吗?当然,match_array?并不存在。

2 个答案:

答案 0 :(得分:1)

查看match_array匹配器的实现:

# An alternate form of `contain_exactly` that accepts
# the expected contents as a single array arg rather
# that splatted out as individual items.
#
# @example
#   expect(results).to contain_exactly(1, 2)
#   # is identical to:
#   expect(results).to match_array([1, 2])
#
# @see #contain_exactly
def match_array(items)
  contain_exactly(*items)
end

contain_exactly方法调用Rspec::BuiltIn::ContainExactly模块:

def contain_exactly(*items)
  BuiltIn::ContainExactly.new(items)
end 

您可以使用对此模块的调用来迭代您需要匹配的数据,并仍然使用match_array方法中的错误消息。 或者,您可以基于BuiltIn::ContainExactly module实现自己的模块。

答案 1 :(得分:0)

我想使用contain_exactly功能,将实际数组重新映射为数组项的id。这类似于您要尝试执行的操作,因此也许会有所帮助。我把它放在/support/matchers/match_array_ids.rb中。

module MyMatchers
  class MatchArrayIds < RSpec::Matchers::BuiltIn::ContainExactly
    def match_when_sorted?
      values_match?(safe_sort(expected), safe_sort(actual.map(&:id)))
    end
  end

  def match_array_ids(items)
    MatchArrayIds.new(items)
  end
end

我还创建了一个测试以测试匹配器是否按预期运行。我把它放在spec/matcher_tests/match_array_ids_spec.rb中。

# frozen_string_literal: true
require 'spec_helper'

RSpec.describe MyMatchers::MatchArrayIds do
  before do
    class ObjectWithId
      attr_reader :id
      def initialize(id)
        @id = id
      end
    end
  end

  context 'when array of objects with ids and array of ids match' do
    let(:objects_with_ids) { [ObjectWithId.new('id1'), ObjectWithId.new('id2')] }
    let(:ids) { ['id1', 'id2'] }

    it 'returns true' do
      expect(objects_with_ids).to match_array_ids(ids)
    end
  end

  context 'when array of objects with ids exist and array of ids is empty' do
    let(:objects_with_ids) { [ObjectWithId.new('id1'), ObjectWithId.new('id2')] }
    let(:ids) { [] }

    it 'returns false' do
      expect(objects_with_ids).not_to match_array_ids(ids)
    end
  end

  context 'when array of objects with ids is empty and array of ids exist' do
    let(:objects_with_ids) { [] }
    let(:ids) { ['id1', 'id2'] }

    it 'returns false' do
      expect(objects_with_ids).not_to match_array_ids(ids)
    end
  end

  context 'when array of objects with ids and array of ids DO NOT match' do
    let(:objects_with_ids) { [ObjectWithId.new('id1'), ObjectWithId.new('id2')] }
    let(:ids) { ['id1', 'id3'] }

    it 'returns false' do
      expect(objects_with_ids).not_to match_array_ids(ids)
    end
  end
end

您可以在以下位置找到基于此内容的示例,该示例基于便签匹配器进行自定义... https://github.com/rspec/rspec-expectations/blob/45e5070c797fb4cb6166c8daca2ea68e31aeca40/lib/rspec/matchers.rb#L145-L196