Thursday, 16 May 2013

When functional tests fail to fail

I have come across a couple of instances recently where the project passed the tests, but really should not have.


Check the record really was changed

If you move your models, controllers and views into sub-directories, form data will get the sub-directory name prepended to the parameters key

Parameters: {"utf8"=>"Ô£ô", "authenticity_token"=>"4", "post"=>{"name"=>"My Post", "text"=>"some text"}, "commit"=>"Submit", "id"=>"3"}

... becomes:
Parameters: {"utf8"=>"Ô£ô", "authenticity_token"=>"4", "subfolder_post"=>{"name"=>"My Post", "text"=>"some text"}, "commit"=>"Submit", "id"=>"3"}

Rails does that automatically, so you may not realise it has happened. In your controller, however, the action method is still looking for params[:post]. Rails does not change that, so when the user tries to edit a record, Rails finds no hash of data for params[:subfolder_post], so assumes there is nothing to change. Then it saves your record, and reports back that everything saved okay!

It gets worse. Your functional test might look like this:

  test "should update post" do
    id = Subfolder::Post.first.id
    put :update, :id => id, :post => { :text => 'modified' }
    assert_redirected_to subfolder_post(assigns(:post))
  end

So you know to change the path and the class name, but you forget to update the params key, because Rails did that for you. And the test passes!

The lesson here is to check the record really was changed:

 test "should update post" do
    id = Subfolder::Post.first.id
    put :update, :id => id, :post => { :text => 'modified' }
    assert_redirected_to subfolder_post(assigns(:post))
    assert_equal 'modified', Subfolder::Post.find(id).drum_text
  end

Check against different users

Another thing to test is that pages will work whether logged in or not. I have several pages that display a little differently depending on whether someone is logged in with a specific role - they see extra links or buttons to secure pages. I already had tests that check you have to be logged into those secure pages, but on the original pages, you do not need to be logged in, so no need to check that, right?

Except sometimes thing change, routes are removed or modified and links fail to work. But the tests do not catch that because I was only testing what a user who is not logged in sees.

The lesson here is to check any page with role-dependant output with both a user not logged in and as an admin with all roles.

No comments: