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

假设我有一个带有redirect_to_baz方法的FoosController

 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 }) 

我查看了文档 ,我尝试搜索response.parameters ,但我没有找到类似的东西。 即使是Hash#to_query似乎也没有解决这个问题。

任何帮助将不胜感激。

从文档中 ,预期的重定向路径可以匹配正则表达式:

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

要validation重定向位置的查询字符串似乎有点复杂。 您可以访问响应的位置,因此您应该能够这样做:

 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"} 

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

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

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

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

 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散列…

我需要类似的东西,最后得到这个:

能够编写测试而不用担心查询参数排序。

 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