[rspec-users] rspec test for converting a hash to a URL string

Pat Maddox pergesu at gmail.com
Mon Apr 14 22:33:10 EDT 2008

On Mon, Apr 14, 2008 at 6:58 PM, Jamie D <jam5t3r.lists at gmail.com> wrote:
> Hi all, I've written an expectation for a method that converts a hash
>  into a url string of name/value pairs. The problem is that the hash is
>  not traversed in the same order as it is defined so I can not work out
>  how to test for the correct returned string. The operation of the code
>  does not require and specific order so I am not going to add a
>  specific order to my method.
>  # test
>  def mappings_data
>   {
>     :shell =>         true,
>     :ftp =>           10,
>     :sql =>           11,
>     :email =>         12,
>     :subdomains =>    13,
>     :parkeddomains => 14,
>     :addondomains =>  15,
>     :transfer =>      16
>   }
>  end
>  it "should map arguments to a url" do
>   @whm.map_args_to_url(mappings_data).should
>  eql("?shell=true&ftp=10&sql=11&email=12&subdomains=13&parkeddomains=14&addondomains=15&transfer=16")
>  end
>  # implementation
>  def map_args_to_url(args={})
>   '?' + args.map { |k,v| "%s=%s" % [URI.encode(k.to_s),
>  URI.encode(v.to_s)] }.join('&') unless args.blank?
>  end
>  # string that is returned
>  "?parkeddomains=14&shell=true&email=12&addondomains=15&ftp=10&subdomains=13&transfer=16&sql=11"
>  _______________________________________________
>  rspec-users mailing list
>  rspec-users at rubyforge.org
>  http://rubyforge.org/mailman/listinfo/rspec-users

You can use the CGI library to parse the query string, and verify that
the hashes are equal.

params = {:foo => true, :bar => 12}
params_as_strings = {}
params.each_key {|key| params_as_strings[key.to_s] = params[key].to_s }
query_string = map_args_to_url params
CGI.parse(query_string.delete("?")).should == params_as_strings

(completely untested, so you'll have to mess with it I'm sure)

That's a bit ugly and verbose, so it may be a good candidate for a
custom matcher

query_string.should equal_query_string("?foo=true&bar=12")

The matcher would call CGI.parse on the actual and expected strings
and verify that they are equal.

Another thing that jumps out at me is that there may be a chance to
build a QueryParams abstraction.  So instead of the above expectation,
you might do

query_params.should == QueryParams.new(:foo => true, :bar => 12)

(you would still have to write a spec verifying the QueryParams#to_s
hash->string conversion of course)

If all you're doing at this point is building that string, then a
QueryParams object is probably overkill.  But I would be ready to move
to it as soon as I started to do any more logic with the query string,
such as asserting that it contains a certain key-value pair.

Like I said at the beginning, this is probably a good situation for a
custom expectation matcher to hide some of the messy details.  Just
keep in mind that the thresholds for creating a custom matcher and
creating a new object are not that far apart, and creating a new
object is generally way more valuable.

(that was almost certainly a lot longer than you wanted, sorry.  I've
just been sick the last couple days and needed to scratch my
list-writing itch :)


More information about the rspec-users mailing list