Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Teaching Your Tests To Report Unused Parameters

Pivotal Labs
Wednesday, January 23, 2008

Recently I was about to check in some changes and did a last minute
click through of the application. All of a sudden I’m staring at a stack
trace. My tests were green and I had functional tests for the failing
controller/action.

Tests are like pants — they cover your backside while you focus on other
things like adding features to your application. Suddenly I felt a
breeze on my cheeks. Something was amiss.

I soon discovered the action and its associated tests had diverged
over time. Some of the parameters were renamed in the action but not
in the functional test. Since some of the work of the action was
conditional on the presence of certain parameters, that work was no
longer being tested.

This exposed weaknesses in the tests and code, such as expected
side effects in the tests that are never checked. If they had been
checked the tests would have failed and the parameter name mismatch
would have been discovered.

Most functional tests provide specific parameters that should at least
be examined during the processing of the action. Reporting unread
parameters would strengthen those tests. It was conceivable to me that
some of the other functional tests had similar unused parameters. I
wanted all of my functional tests to report all unused parameters.

The first step was to instrument the params hash. I wanted to track
access to the params hash and report parameters that were not read
during the processing of the action. I don’t know what all is done to
params during the lifecycle of a test. I’m only interested in access
from the time the action starts till it returns so I need to be able
to turn the tracking on and off at specific times.

It turns out that Rails uses a subclass of Hash called
HashWithIndifferentAccess.
I added my changes to
HashWithIndifferentAccess in test/test_helper.rb:

class HashWithIndifferentAccess
  def [](key)
    @accessed_keys ||= {}
    @accessed_keys[key] = true
    super
  end

  def start_logging
    @accessed_keys = {}
  end

  def end_logging
    @accessed_keys['action'] = true
    @accessed_keys['controller'] = true
    never_accessed = []
    self.each_key do |key|
      never_accessed << key unless @accessed_keys.include?(key)
    end
    raise "Some keys never accessed: #{never_accessed.join(', ')}" unless never_accessed.empty?
  end
end

With these changes an exception will be raised if any first level keys
are not read between start_logging
and end_logging.

In each of my functional tests I added code similar to this (from account_controller_test.rb):

class AccountController
  around_filter :check_params
  private
  def check_params
    params.start_logging
    yield
    params.end_logging
  end
end

The around filter starts and ends the logging in the context of the
action.

With these changes in place my tests no longer passed and my
backside was warm and protected again.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

4 Comments

  1. Bryan Helmkamp says:

    Webrat, a plugin I wrote to do acceptance testing with Rails, protects your functional tests from a parameter name breakage.

    http://agilewebdevelopment.com/plugins/webrat

    January 23, 2008 at 8:10 pm

  2. jeff says:

    very clever

    January 23, 2008 at 8:15 pm

  3. Scott Woods says:

    I really like the idea of expanding the test framework this way — it’s great information for the developer, it doesn’t bog down production code, and the errors are presented at just the right time in the workflow (during testing).

    Do you run into problems with some of the extra params that rails inserts that you don’t routinely use in your actions? I see the exclusions for “action” and “controller”, but what about “format” and “commit”? (For those who are wondering, “format” contains the file-like extension on the end of a rails 2.0 URL, such as “xml”, and “commit” contains the text of the form button, if the action was invoked via a form).

    On a side note: If you’re interested in actually enforcing your params/protocol interface to your controllers in all environments (not just test), our company wrote a plugin called assert_request that allows you to do just that:

    http://validaterequest.rubyforge.org/

    Of course, our plugin serves a slightly different (more paranoid) purpose. It also has a performance penalty (unmeasured, as of yet) since it runs in production, and you have to declare which params are permitted at the beginning of your actions. Good stuff for writing a strict, robust application, but certainly not for everyone.

    Thanks for the great post and idea. This will scratch a great itch for us, for those times when we don’t need the tight security of assert_request, but still want to know about orphaned or extra params. It seems like just about any Rails developer would benefit from including this in their test helper.

    January 30, 2008 at 6:48 am

  4. Kelly Felkins says:

    Scott,

    Thanks for the kind words.

    Regarding: “Do you run into problems with some of the extra params that rails inserts…”

    As you pointed out, I added ‘action’ and ‘controller’. I’ve only used this technique when updating an existing, simple project and I didn’t run into any other rails added params but you are correct that these will have to be addressed.

    Thanks again for checking in.

    January 31, 2008 at 5:45 pm

Add New Comment Cancel reply

Your email address will not be published.

Pivotal Labs

Pivotal Labs

Recent Posts

  • Does the set of all sets contain itself?
  • Standup 3/8/2012
  • Standup 3/7/2012
Subscribe to Pivotal's Feed

Author Topics

riddles (1)
agile (167)
capistrano (2)
rails (26)
movember (1)
git (10)
railsdoc (1)
object-design (1)
bdd (3)
cucumber (3)
linkedin (1)
oauth (1)
ruby (17)
tdd (2)
lvh.me (1)
rails 3.1.1 (1)
selenium (6)
homebrew (1)
mysql (5)
rvm (1)
sproutcore (1)
paperclip (2)
pry (1)
amazon (1)
heroku (1)
rails3 (2)
jasmine (3)
design (3)
process (12)
productivity (8)
learning (1)
olin (1)
migrations (2)
mongodb (2)
devise (2)
javascript (13)
rubymine (4)
ipad (1)
whurl (1)
head.js (1)
pairing (2)
tools (4)
pair programming (1)
rspec (10)
rspec2 (1)
ruby19 (1)
incubation (3)
startup (5)
api (1)
presenter (1)
vanna (1)
pivotal tracker (5)
capybara (1)
fakeweb (1)
webmock (1)
intern (1)
ruby on rails (25)
meetup (1)
textmate (1)
testing (20)
solr (4)
nyc-standup (11)
community (1)
opensource (3)
activerecord (4)
chrome (1)
mp4 (1)
activeresource (1)
flash (3)
neo4j (1)
nginx (1)
rsoc (1)
meta programming (1)
agile standup (7)
government (3)
webos (4)
xss (1)
jquery (1)
bundler (2)
ci (3)
gems (5)
postgresql (1)
geminstaller (1)
gemcutter (1)
cloud (2)
rack (2)
refraction (1)
gem (5)
refactoring (1)
validations (1)
webrat (1)
engine-yard (1)
firefox (2)
jsunit (1)
mongrel (2)
thin (1)
unicorn (1)
facebook (1)
rubygems (5)
jruby (1)
actioncontroller (1)
rails 2.3 (1)
palmpre (1)
autotest (1)
mac (2)
hosting (1)
goruco (11)
database (3)
railsconf (11)
gogaruco (4)
deployment (4)
github (1)
ie (1)
ajax (1)
intellij (1)
json (1)
asset packaging (1)
polonium (1)
character encoding (1)
utf-8 (1)
test (3)
civics (1)
hpricot (1)
rake (3)
sms (1)
unicode (1)
iphone (1)
java (1)
safari (1)
memory leaks (1)
rr (3)
editor (1)
css (1)
nyc (3)
performance (5)
fun (5)
enterprise rails (1)
health (1)
new and cool (1)
general (2)
treetop (1)
errors (1)
stack (1)
trace (1)
cache (1)
cookies (1)
freesoftware (1)
conferences (1)
development (1)
driven (1)
proxy (1)
caching (1)
peertopatent (1)
languages (1)
rest (2)
rubyforge (1)
sake (1)
file (1)
upload (1)
constants (1)
osx (1)
terminal (1)
pairprogramming (2)
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >