Is Your Test Suite Acceptable?

Posted by Jeremy Voorhis Fri, 25 Aug 2006 23:43:00 GMT

Is your test suite acceptable? I mean acceptable in the Chomsky sense of the word. Here are a few heuristics:

  1. Do you understand your test at first glance?
  2. Do you understand the code that is being exercised after reading your test?
  3. Do your tests tend to have 1 assertion or 10 assertions? More?
  4. Do your tests have cryptic names, like test_component?
  5. Are you using external test fixtures? If so, how much time do you spend reading and cross-referencing them?
  6. If you are using external test fixtures, how well do they serve your needs? Are you creating tests that require you to cross reference external fixtures and temporary objects?

Here are some design principles that are useful for lowering the mental overhead your test suite requires:

Give your tests meaningful names

If you can accurately infer what your test is trying to accomplish by reading its method name, you can understand it much faster. It’s even more helpful when that name appears in a report generated by a test runner!

Favor acceptability over DRYness

Which is worse: repeating a string literal two or three times within a test, or losing time reading the test later? Of course, this is a tradeoff, and both sides have cumulative effects.

Group your tests according to their context

Just because all of your tests exercise the same class, they don’t all have to live together. If you are testing a Stack class, don’t be afraid to separate your tests for an empty stack and your tests for a full stack. You can then use the setup method to instantiate the kind of stack you are testing, and your tests will be easier to understand. Conversely, when tests that are grouped together rely on different contexts, you will spend longer establishing your mental model when you read these tests later.

Write individual tests for a method’s individual behaviors

Rather than writing one test for one method, try analyzing the expectations you are placing on your method. Let’s use a method that accepts a blob, generates a filename and saves the blob to the named file as an example. Write one test to ensure the file name is generated correctly, and write another test to ensure the contents on disk are correct.

Keep your tests short

If you can use setup or some other means to create all the context you need, and your tests target individual behaviors, you can write a suite of tests that is very scannable by human eyes.

Avoid external fixtures when feasible

Relying on external fixtures may cause you to spend much time cross-referencing your test against many fixture files. What’s worse, changing an external fixture for one test may have the side effect of breaking other tests!

Posted in Testing | 5 comments

Is your test suite valuable?

Posted by Jeremy Voorhis Mon, 21 Aug 2006 21:39:00 GMT

Is your test suite valuable? I mean, is it actually making your code better? Answer the following questions to find out.

  1. Are your tests inexpensive to run?
  2. Are there any inhibitions to running your full suite of unit tests before every check-in?
  3. Is the process of running tests uncomplicated?
  4. Do all of your tests pass?
  5. In practice, are your tests your first line of defense against new bugs? Ideally, you can know if you have introduced a bug within minutes.
  6. Is test-first development actually preferred by your team? Writing tests should be rewarding.

Posted in Testing | 5 comments

Howto Make A Fixture Available in All Tests

Posted by Jeremy Voorhis Mon, 08 May 2006 03:43:00 GMT

In test/test_helper.rb:


class Test::Unit::TestCase
  def self.fixtures_with_users *names
    self.fixtures_without_users [:users, *names]
  end
  class << self; alias_method_chain :fixtures, :users end
end

Does anybody know another way to do this?

Posted in Rails, Testing | 3 comments

The Death Knell for TDD

Posted by Jeremy Voorhis Sun, 16 Oct 2005 18:30:00 GMT

RubyConf has wrapped up and as you would expect, it has left us with some great, new ideas to chew on.

One of the most exciting ideas to me is Obie’s new DSL for a specification framework in Ruby. According to his most recent blog post, his muse came to him after pairing with Aslak on the RSpec code at RubyConf. The language has a concept of Stories, Actors and Scenarios, and replaced the long and banal underscore-separated method names that you’re probably used to with a much more natural free-form human readable string.

If you’re impatient and you want to migrate away from TDD right now, I recommend you check out RSpec, but definitely keep an eye on Obie – he’s on fire!

Posted in Testing, Ruby, web development, Rails | 1 comment

BDD, RSpec and RUnit

Posted by Jeremy Voorhis Wed, 28 Sep 2005 04:04:00 GMT

Today on #ruby-lang, I was enlightened to the latest XP-inspired testing paradigm: Behaviour Driven Development, as well as srbaker’s implementation of RSpec. It seems like a really great idea – testing semantically, rather than per-module or per-method. I’m not quite sure, however, why a new testing framework is needed. Today, I wrote multiple tests for a method with RUnit:

Event#find_event_in_range_of_time is tested with EventTest#test_find_event_in_range_of_time_for_organization

and

EventTest#test_find_event_in_range_of_time_for_range.

Granted, I haven’t tried RSpec yet, and I do not want to discount srbaker’s work – he is a smart developer – but I am not sure why another testing framework is needed for Ruby. It seems like either way you end up with a somewhat larger mass of tests for specific behaviours, and RUnit is nicely baked into Rails.

Any comments, guys?

Posted in Rails, web development, Ruby, Testing | 1 comment | no trackbacks