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:
- Do you understand your test at first glance?
- Do you understand the code that is being exercised after reading your test?
- Do your tests tend to have 1 assertion or 10 assertions? More?
- Do your tests have cryptic names, like
test_component?
- Are you using external test fixtures? If so, how much time do you spend reading and cross-referencing them?
- 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
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.
- Are your tests inexpensive to run?
- Are there any inhibitions to running your full suite of unit tests before every check-in?
- Is the process of running tests uncomplicated?
- Do all of your tests pass?
- 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.
- Is test-first development actually preferred by your team? Writing tests should be rewarding.
Posted in Testing | 5 comments
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
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
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