Using non text values as arguments in functional tests

When running functional tests, You use methods like get, post, etc. a lot. They take as arguments action name to call (as a symbol) and hash with parameters. But You need to remember that this hash it is not exactly the same what params object is (from controller side).

The main difference is that params is (more or less) hash with elements being strings or other params-like hashes (results of processing HTML forms with fields named with Rails conventions object[attribute_name]). And when You call get/post from functional test, parameters hash is full blown Ruby hash and as such is passed to controller, without any changes. So it is possible to pass whole Ruby objects as values in params in test environment.

For example if You expect argument params[:time] and run Time.parse(params[:time]) in controller You will encounter error (like: NoMethodError: private method `gsub!' called for Tue Dec 23 01:06:08 +0100 2008:Time) running test if You call action with get :action, :time => Time.now. For other objects You could get other errors, but what is most important – in such case Your tests are not modeling real environment! Arguments tests are passing to controller methods have different types and can behave quite differently than when faced with real HTTP request.

It could be more cumbersome when You use respond_to to dispatch rendering on requested content type and use following sequence in test:

get :action, :id => some_id, :format => :csv
assert_response :success

Do You spot pitfall? Assuming controller’s rendering statement looks like:

  respond_to do |wants| 
     wants.html;
     wants.csv { 
        #render some CSV
     }
  end

Assertion will fail with Expected response to be a <:success>, but was <406>. HTTP 406 Not Acceptable? Yes, since this is response Rails should give when they can not provide answer with required content type. Somewhere inside of Rails Mime::Type lookup fails since it expects argument to be string ('csv') not a symbol (:csv). So, remember to specify format as :format => 'csv' (as string not a symbol).

Could Rails protect me from this kind of errors?

I don’t see any reasons not allowing to implement casting to strings all values (except hashes which should be processed recursively), but I’m not core Rails hacker – maybe there is a reason to such behavior.

Lesson from this – always use only strings and hashes as objects passed to controllers in functional tests.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.