我可以在自定义匹配器中使用内置的RSpec匹配器吗?

awe*_*ndt 5 ruby rspec rspec-expectations

我对功能规格有以下期望(相当低级,但仍然有必要):

expect(Addressable::URI.parse(current_url).query_values).to include(
  'some => 'value',
  'some_other' => String
)
Run Code Online (Sandbox Code Playgroud)

请注意,第二个查询值是模糊匹配,因为我只想确保它在那里,但是我不能更具体地说明它。

我想将其提取到自定义匹配器中。我开始于:

RSpec::Matchers.define :have_query_params do |expected_params|
  match do |url|
    Addressable::URI.parse(url).query_values == expected_params
  end
end
Run Code Online (Sandbox Code Playgroud)

但这意味着我无法通过{'some_other' => String}那里。为了继续使用模糊匹配,我必须include在自定义匹配器中使用匹配器。

但是,其中的所有内容RSpec::Matchers::BuiltIn都标记为专用API,Include具体记录为:

# Provides the implementation for `include`.
# Not intended to be instantiated directly.
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是:RSpec支持在自定义匹配器中使用内置匹配器吗?我该怎么做?

Dav*_*uth 7

RSpec::Matchers似乎是受支持的 API(它的 rdoc 没有另外说明),因此您可以在 Ruby 中编写匹配器,而不是在匹配器 DSL(受支持;请参阅自定义匹配器文档的第二段)中,并RSpec::Matchers#include像这样使用:

规格/支持/matchers.rb

module My
  module Matchers
    def have_query_params(expected)
      HasQueryParams.new expected
    end

    class HasQueryParams
      include RSpec::Matchers

      def initialize(expected)
        @expected = expected
      end

      def matches?(url)
        actual = Addressable::URI.parse(url).query_values
        @matcher = include @expected
        @matcher.matches? actual
      end

      def failure_message
        @matcher.failure_message
      end

    end
  end
end
Run Code Online (Sandbox Code Playgroud)

规格/支持/matcher_spec.rb

include My::Matchers

describe My::Matchers::HasQueryParams do
  it "matches" do
    expect("http://example.com?a=1&b=2").to have_query_params('a' => '1', 'b' => '2')
  end
end
Run Code Online (Sandbox Code Playgroud)