The Testing Anti-Patterns Drafts (draft 3) : Testing a class with itself
George Malamidis, October 22nd, 2006Among other interesting engineering marvels, cars tend to have an accelerator and a speed meter. It would obviously make sense to test both in order to verify whether they’re doing their job properly.
If a test consists of putting the pedal to the metal and watching the speed meter react, would that give us confidence that the accelerator works as intended? To an extend, it would, especially if the speed meter has had its own fair share of testing. However, if a couple of days down the line somebody worked on the speed meter to give it a stylish racing white panel and accidentally broke the way the meter displays speed, the accelerator test would erroneously indicate that the accelerator is broken.
This kind of danger is apparent when testing a class’s methods with other methods of the same class:
class Repository
def save record
OrmFramework.save record
end
def load id
OrmFramework.load id
end
end
class RepositoryTest < Test::Unit::TestCase
def test_should_save_record
record = Record.new
repository = Repository.new
repository.save record
assert_equal record, Repository.load record.id
end
end
If we changed the implementation of the load method, the test_should_save_record test would potentially break, although the save method still works as intended. A more sane test would look like:
def test_should_save_record record = Record.new Repository.new.save record assert_equal record, OrmFramework.load record.id end
The important detail is that OrmFramework is an external import, whose implementation we know is not going to change and we can assume it has been tested to work as expected. The moral is to avoid testing code with code that has not been frozen and is still code in progress.
If you’d like to follow the discussion, feel free to grab The Testing Anti-Patterns Drafts feed.
