Ruby o Rails Rspec - 如何在创建自定义匹配器时验证参数

时间:2018-02-02 05:38:43

标签: ruby-on-rails rspec

我想创建一个像matcher has_http_status一样的验证到content_type。

我创建了以下匹配器:

require 'rspec/expectations'

RSpec::Matchers.define :have_content_type do |expected|
  match do |actual|
    actual.content_type == expected
  end

  description do
    "respond with content_type #{expected}"
  end
end

但是,我想检查实际值是否为响应对象。如果没有,我想给出一条像have_http_status这样的消息:

 Failure/Error: it { expect(legal_person).to have_http_status(200) }
       expected a response object, but an instance of LegalPerson was received
     # ./spec/controllers/legal_people_controller_spec.rb:105:in `block (5 levels) in <top (required)>'

因此,当我传递一个与请求 - 响应对象不同的对象时,我会发出一个错误,指出响应对象是预期的。

没有它可行,但如果它显示一条信息性消息,说明确切地说出了什么问题,那就更好了。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

您尝试在1个名称下拥有2个匹配器。我认为这是一个不好的做法,应该有两个匹配器 - 一个用于内容类型,另一个用于检查请求/响应类型。所以你的测试应该是这样的:

expect(response).to be_a(ActionDispatch::Response)
expect(response).to have_content_type('application/json')

另外,我没有看到任何内容类型检查的问题。如果传递的对象没有.content_type方法,匹配器将抛出相应的错误:Undefined method 'content_type'你应该很好地搞清楚你是否传递了错误的对象。

但是,如果您仍然确定需要在一个匹配器中检查两件事,请检查:

RSpec::Matchers.define :have_content_type do |expected|
  match do |actual|
    request_or_response?(actual) && actual.content_type.to_s == expected
  end

  description do |actual|
    if request_or_response?(actual)
      "respond with content_type #{expected}"
    else
      "a response object, but an instance of #{actual.class} was received"
    end
  end

  private

  def request_or_response?(actual)
    [Rack::Request, ActionDispatch::Response].any? do |klass|
      actual.is_a?(klass)
    end
  end
end