RSpec测试使用GET参数重定向到URL

时间:2014-05-28 22:31:38

标签: ruby-on-rails ruby rspec parameters response

假设我有FoosController redirect_to_baz方法。

class FoosController < ApplicationController

  def redirect_to_baz
    redirect_to 'http://example.com/?foo=1&bar=2&baz=3'
  end

end

我正在使用spec/controllers/foos_controller_spec.rb测试此内容:

require 'spec_helper'

describe FoosController, :type => :controller do

  describe "GET redirect_to_baz" do
    it "redirects to example.com with params" do
      get :redirect_to_baz
      expect(response).to redirect_to "http://example.com/?foo=1&bar=2&baz=3"
    end
  end

end

有效。但是,如果有人交换查询字符串参数(例如http://example.com/?bar=2&baz=3&foo=1),则测试失败。

测试这个的正确方法是什么?

我想做点什么:

expect(response).to redirect_to("http://example.com/", params: { foo: 1, bar: 2, baz: 3 })

我查看了documentation,我尝试搜索response.parameters,但我没有找到类似的内容。即使Hash#to_query似乎也无法解决这个问题。

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:25)

documentation,预期的重定向路径可以匹配正则表达式:

expect(response).to redirect_to %r(\Ahttp://example.com)

要验证重定向位置的查询字符串似乎有点复杂。您可以访问响应的位置,因此您应该可以执行此操作:

response.location
# => http://example.com?foo=1&bar=2&baz=3

您应该能够像这样提取查询字符串参数:

redirect_params = Rack::Utils.parse_query(URI.parse(response.location).query)
# => {"foo"=>"1", "bar"=>"2", "baz"=>"3"}

从中可以直接验证重定向参数是否正确:

expect(redirect_params).to eq("foo" => "1", "baz" => "3", "bar" => "2")
# => true

如果你不得不多次执行这种逻辑,那么将它们全部包装到自定义的rspec匹配器中肯定会很方便。

答案 1 :(得分:5)

您是否能够使用路径助手而不是普通字符串?如果是这样,您可以将哈希参数传递给路由助手,它们将被转换为查询字符串参数:

root_url foo: 'bar', baz: 'quux'
=> "http://www.your-root.com/?baz=quux&foo=bar"
expect(response).to redirect_to(root_url(foo: 'bar', baz: 'quux'))

这有帮助,还是仅限于使用字符串而不是路由助手?

另一个想法是你可以直接断言params散列中的值而不是url +查询字符串,因为查询字符串params将序列化为params散列...

答案 2 :(得分:2)

我需要类似的东西,结果是这样:

能够编写测试,而不必担心查询参数的顺序。

expect(response.location).to be_a_similar_url_to("http://example.com/?beta=gamma&alpha=delta")

将以下内容拖放到./spec/support/matchers/be_a_similar_url_to.rb

RSpec::Matchers.define :be_a_similar_url_to do |expected|
  match do |actual|
    expected_uri = URI.parse(expected)
    actual_uri = URI.parse(actual)

    expect(actual_uri.host).to eql(expected_uri.host)
    expect(actual_uri.port).to eql(expected_uri.port)
    expect(actual_uri.scheme).to eql(expected_uri.scheme)
    expect(Rack::Utils.parse_nested_query(actual_uri.query)).to eql(Rack::Utils.parse_nested_query(expected_uri.query))
    expect(actual_uri.fragment).to eql(expected_uri.fragment)
  end

  # optional
  failure_message do |actual|
    "expected that #{actual} would be a similar URL to #{expected}"
  end

  # optional
  failure_message_when_negated do |actual|
    "expected that #{actual} would not be a similar URL to #{expected}"
  end
end