Real World Unit Tests

Theoretically all of your code should be covered by unit tests (although it is common to ignore simple properties). For help with this see NCover hopefully this will soon get a VS.NET addin.

If you are really lucky you are working on a greenfield project that has clear static requirements, a simple yet detailed design document, a full set of acceptance tests and plenty of time to write the unit tests. However in the real world you don’t have any of these.

Typically you will have an existing code base, some of which is covered by unit tests and the others not.

You need to prioritise where to write the unit tests.

Carefully constructed tests can excercise a large part of the system in a few tests.
For example if you use a Facade to import data into the system (considered an atomic step, but actually exercising a lot of validation, parsing and persistance code) you can exercise the most frequently used 25% of the system in a handfull of tests.

If a test fails you can use other smaller more detailed tests to narrow down the error.
The only downside to this is that a single error in a fundamental system can cause hundreds of failures.

If one area of the system has failed frequently over a number of builds then it is an obvious target for some new unit tests.

If any area of the system includes scripting, dynamic sql  or stored procedures they need to be called at least once by the unit tests. This will excercise the database creation script during either the build process or by the Continous Integration server (You do create a new database as part of your build process don’t you?). Anything that is not checked by the compiler is ripe for typos to cause havoc. Stored procedures are great – when compiled they report certain errors (the sql does not make sense) however they can ignore the fact that tables or fields do not exist.

Tests need to be fragile with respect to the functionality tested, but be immune to minor changes in call symantics. This is where some simplifying Facades really help – they isolate the test code from change, encourage reuse, make the test code easier to read and can provide ideal debugging fodder (either after the test has been run or set breakpoints and run a single test).

Most useful XP Idea

XP is a collection of development practices that can if used in concert speed up application development in the face of changing requirements and most of the time requirements change. Some of the practices are there to cover for weaknesses in the other practices, for example refactoring is dangerous without detailed unit tests.

If you want to ignore most of the XP practices the best to adopt would be the automated unit tests. These are developer tests, not formal QA acceptance or regression tests. Things that should be tested here are that the stored procedures actully exist, that they run with typically data without catastrophic failures. It is best to think of these as a replacement for asserts.
(Personally I replace any assert that will stop program execution with an equivalent exception – this makes it far more friendly to a unit test.)
An assert will warn you that an error condition occours while a unit test demonstrates what happens when the error condition occours.

There is a problem with the typical gui unit test addins – they write one stub test per public or protected method. This creates lots of almost irrelevent tests. The best way to think of unit testing is in terms of  testing buisness functionality. This allows unit tests to be used as documentation of buisness scenarios. Plus if you omit to reset your database in the teardown (and always reset the database in the setup) then you have the oppertunity to have a tested buisness scenario that can be used as the starting point for manual UI testing. This technique alone saves hours of debugging time – write a test to recreate the exact condition that you are looking for and if you go one line too far in the debugger and destroy the test condition it is usually a matter of seconds before you can recreate the exact data that you were using.

Automated Unit tests become especially valuable when you are working across multiple streams of development. The project I am currently working on has 4 current development streams (one pure development plus three live customer streams). Since these are slowly diverging (certain new features only get added to the later streams – fixes to those units in older streams cause divergence) a fix or enhancement may need to be implemented in several places.

Tests need to be focused (test one functional area) and atomic (failure of one test should not stop the system).  It is fine (even preferable) to use parts of your system to setup tests for other areas.The test framework that I use has a set of Facades that abstract away parts of the system and uses them to simplify tests. 

For example if your system delt with processing customer orders (these arrive as XML documents) you could write a Facade around the code that parses and stores the incoming document and use other classes to generate the data.

So the start of the test would be:

    TOrderImporterFacade.ImportOrder( TSimpleOrder, 100, ‘FooBar’ );

This would use the class TSimpleOrder to create a order for 100 FooBar’s

You could then check the outstanding orders

   CheckEquals(100, TStockFacade.OpenOrdersCount(), ‘Before Restocking’);

Use another Facade to perform the buiness functions.

   TBuisnessFacade.Restock();

And again peform the same check.

   CheckEquals(100, TStockFacade.OpenOrdersCount(), ‘After Restocking’);

This technique is less fragile with respect to functional changes, the tests are far easier to read,
and it is very easy to add a new buiness scenario as an experiment.

XP Values, Practices and Principles

Here are the XP

Values:

  • Communication (possibly Visibility)
  • Simplicity
  • Feedback (formerly Testing)
  • Courage (formerly Aggressiveness) (See: XpCourageValue)
  • Respect

Practices:

Principles

Fundamental Principles:

  • Rapid Feedback
  • Assume Simplicity
  • Incremental Change
  • Embracing Change
  • Quality Work

Further Principles:

  • Teach Learning
  • Small Initial Investment
  • Play to Win
  • Concrete Experiments
  • Open, honest Communication
  • Work with people’s instincts – not against them
  • Accepted Responsibility
  • Local Adaptation
  • Travel Light
  • Honest Measurement