Pro-Test: Avoiding DDT

Here's a situation I often find myself in: I'm writing two routines that share essentially identical structure and differ only on a few values. The obvious DRY approach is to put the common stuff in a single subroutine and the specific stuff in two wrappers. Simple enough.

function a {
  do X with 'a', do Y with 1
}

function b {
  do X with 'b', do Y with 2
}

becomes:

function a {
  call c('a', 1)
}

function b {
  call c('b', 2)
}

function c {
  do X with first param, do Y with second param
}

But when it comes to testing, we face a decision. Obviously a unit test for the common subroutine would make sense. But how do we write tests for the two wrappers? It would certainly be DRY to make those tests simply confirm that the wrappers are passing the correct parameters to the common subroutine. Very easy to do, but it falls into the "Development-Driven Testing" (DDT) trap. Because in this simple, intuitive step we have just encoded implementation details into our tests and made it much more difficult to adjust that implementation later on down the road should the need arise.

Since a and b are wrappers around c, they really aren't units in and of themselves that should be tested as such. They are actually layers, kinda like an onion, so the unit that should be tested includes the inner subroutine. So how can we accomplish this testing without repetition? The tests should be structured similarly, with common testing code broken out:

function test_a {
  call test_common(a, 'a', 1)
}

function test_b {
  call test_common(b, 'b', 2)
}

function test_common {
  ensure that calling first param does X with second param, and does Y with third param
}

Writing a test for c itself is not necessarily required if it is never used on its own, but if you choose to do so, it should be written so that it and test_common are not redundant.

Are there times when DDT is unavoidable? Sure. As we all know DDT is an effective bug-killing agent, so it is needed sometimes to retro-fit a test suite onto a previously built system that you can't afford to refactor en masse. Sometimes you really do have to test layers of the onion. But prolonged exposure certainly has deleterious effects, so it is definitely not recommended for organically grown software.

Trackback URL for this post:

http://tigretigre.com/trackback/19

Comments

Pingback

[...] Pro-Test: Avoiding DDT | tigretigre.com tigretigre.com/content/pro-test-avoiding-ddt – view page – cached The perils of Development-Driven Testing Tweets about this link Topsy.Data.Twitter.User['tigregeek'] = {"location":"Boston","photo":"http://a3.twimg.com/profile_images/92012743/IMG00400_normal.jpg","name":"Titi Alailima","url":"http://twitter.com/tigregeek","nick":"tigregeek","description":"Polymath autodidact software engineer/architect","influence":""}; tigregeek: “Pro-Test: Avoiding DDT http://tigretigre.com/content/pro-test-avoiding-ddt ” 5 days ago view tweet retweet Filter tweets [...]

Other variations

In case you're interested, here's some great write-ups on Development-Driven Development and Test-Driven Testing and, my personal favorite, Document-Driven Documentation.