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

Duplicate test name detection

Pivotal Labs
Tuesday, January 13, 2009

Ruby does not throw any exceptions or warnings if an object defines two methods with the same name. The second definition always wins. While this provides great flexibility for many Ruby tasks it can be problematic when writing tests. In particular, if you define two tests with same name in the same test class, one will get run and the other will not. If you have been writing tests for a while you understand that there is nothing worse than writing a test that never gets used!

Recently Matthew O’Connor and I set out to fix this problem for Test::Unit by alias method chaining :method_added for TestCase classes and their subclasses. We use the inherited hook on Ruby classes to dynamically define a method_added hook for every test case. This is required because method_added does not get inherited between classes, so it can’t be defined only in Test::Unit::TestCase.

The following patch raises an exception if it detects a duplicated test name.

class Test::Unit::TestCase
  class << self
    def known_test_methods
      @known_test_methods ||= Array.new
    end

    def record_test_method(method)
      if method.to_s.starts_with?("test")
        if known_test_methods.include? method
          raise "Duplicate test #{self}##{method}"
        else
          known_test_methods << method
        end
      end
    end

    def inherited(subclass)
      class << subclass
        def method_added_with_duplicate_check(method)
          record_test_method(method)
          method_added_without_duplicate_check(method)
        end
        alias_method_chain :method_added, :duplicate_check unless method_defined?(:method_added_without_duplicate_check)
      end
    end
  end
end

When we first tried this against a legacy code base we found almost a dozen duplicated tests that were not running.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

8 Comments

  1. Josh Susser says:

    Very useful check! But where did you hear that `method_added` wasn’t inherited? I’ve used it before and just double-checked again right now, and it inherits just fine. I also don’t see the need for doing an alias method chain. Just override method_added in TestCase and call super at the end.

    class Test::Unit::TestCase
    class << self
    def known_test_methods
    @known_test_methods ||= Array.new
    end

    def method_added(method)
    if method.to_s.starts_with?(“test”)
    if known_test_methods.include?(method)
    raise “Duplicate test #{self}##{method}”
    else
    known_test_methods << method
    end
    end
    super
    end
    end
    end

    January 14, 2009 at 5:43 am

  2. Adam Milligan says:

    This is great stuff; the sort of thing that testing frameworks should have built in.

    January 14, 2009 at 6:31 am

  3. Pat Nakajima says:

    Great check! I added a similar hook to my [fixjour](http://github.com/nakajima/fixjour) project to make sure people don’t define redundant builder methods: [http://github.com/nakajima/fixjour/blob/master/lib/fixjour/redundant_check.rb](http://github.com/nakajima/fixjour/blob/master/lib/fixjour/redundant_check.rb).

    January 14, 2009 at 7:19 am

  4. grosser says:

    just switch to rspec/should/anything better then pure test and do yourself+everybody reading your code a favor + no need to worry about such wacky details

    January 14, 2009 at 8:47 am

  5. Chris Heisterkamp says:

    Josh,

    You’re absolutely right about method_added inheriting in Ruby. We initially tried your method but something in our code base (Ruby 1.8.6 / Rails 2.0.2) seems to break/override this inheritance for test cases.

    The alias method chain was added because we didn’t want to make assumptions about whether or not these classes might already have a method_added, potentially blowing them away.

    January 14, 2009 at 5:49 pm

  6. Chris Heisterkamp says:

    Grosser,

    We would love to use alternate frameworks, but we’re working with a large legacy code base and it’s not worth the time right now to introduce a new testing framework.

    January 14, 2009 at 5:53 pm

  7. Ryan Sobol says:

    Great piece of engineering work!

    January 14, 2009 at 6:46 pm

  8. Ryan Davis says:

    ruby -w?
    rake?
    $-w = true?

    January 14, 2009 at 8:28 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 >