Introduction

In our quest to produce quality software and our relentless use of automated unit tests in our development activities, we’ve come to realize they possess other virtues as well. One of those being they stand as a documentation of the system being developed. I’ve taught this idea in several agile and TDD courses. In this blog I want to give you an example of how that may be. I’m purposely not discussing executable specifications and Behaviour Driven Development as it would make this blog too long. My goal is to show how using some convention and Visual Studio 2010 can go a long way in cranking up your unit tests another notch.

Documentation of API usage

One clever use of unit tests is for learning a new API or even a new language. Writing several assertions to validate our understanding and assumptions about an API usage is very rewarding as the feedback is rapid and progress towards a goal is constantly measured. These learning tests may be kept around to document the assumptions made that constitute the basis of our solution. Here is an example of a learning test for the Character.IsWhiteSpace() method of the BCL. [TestMethod] [Description(@"White spaces are the following characters: ' ', 't', 'n', 'r'")] public void May_be_a_white_space() {   Assert.IsTrue(char.IsWhiteSpace(' '));   Assert.IsTrue(char.IsWhiteSpace('n'));   Assert.IsTrue(char.IsWhiteSpace('t'));   Assert.IsTrue(char.IsWhiteSpace('r'));   Assert.IsFalse(char.IsWhiteSpace('A'));   Assert.IsFalse(char.IsWhiteSpace('+')); } A test can also document how to use the classes we create in our solutions. The following is an example of such a test. In our chess software, this unit test documents the way of obtaining a chess piece which is to call the NewPiece() factory method and passing it a color (either Color.White or Color.Black) and a Kind (such as Kind.Pawn) as arguments. [TestMethod] [Description("A chess piece consists of a kind and a color that are specified when the piece is created")] public void Should_retain_its_color() {   Piece pawn = Piece.NewPiece(Color.Black, Kind.Pawn);   Assert.IsTrue(pawn.IsBlack);   Assert.IsFalse(pawn.IsWhite);   pawn = Piece.NewPiece(Color.White, Kind.Pawn);   Assert.IsTrue(pawn.IsWhite);   Assert.IsFalse(pawn.IsBlack); }

Documentation of behaviours

Unit tests document behaviours of our code. Test classes should be given names that provide context for all the test methods they contain. [TestClass] public class When_displaying_a_board {   [TestMethod]   public void A_black_queen_should_show_as_Q()   {     …   }   … } Test methods should also be named in such a way that the behaviour they validate is evident. [TestMethod] [Description("The board is displayed on 8 lines with blacks pieces on line 8 and 7 and white pieces on lines 1 and 2")] public void It_should_show_all_pieces_in_their_initial_position() {   Assert.AreEqual(     "RNBQKBNR".Line() +     "PPPPPPPP".Line() +     "........".Line() +     "........".Line() +     "........".Line() +     "........".Line() +     "pppppppp".Line() +     "rnbqkbnr".Line(),     board.ToString()   ); } Notice that, instead of writing comments, I’m using the Description attribute to tie the behaviour being tested with some requirement or specification of the system. Personally, I’m not doing anything fancy with these descriptions, but you can imagine using a pattern that would provide more traceability in your environment as in the following. [TestMethod] [Description("US 234: Black pawns are shown as P, white pawns are shown as p")] public void A_white_pawn_should_show_as_p() {   Piece whitePawn = Piece.NewPiece(       Color.White,       Kind.Pawn);   Assert.AreEqual("p", whitePawn.ToString()); }

Documentation of design specifications

Now comes the fun part! Because of the thought we’ve put in selecting meaningful names when the tests are executed in Visual Studio we get a result screen that looks like this. Explicit names Notice how combining our test class and method names reads like a phrase that documents the design of our software. If we group the results by Description, we get a list of all the requirements of our software. descriptions as specifications If we expand one of the requirements, we see all the tests that validate it so we can trace back to the code that implements it. traceability

Conclusion

I hope I’ve convinced you that tests can serve as documentation using simple tricks, conventions and tooling you may already have at your disposal. Because this documentation is embedded in code it has a lot more chance of being maintained as the code evolves. These techniques require agreement amongst team members but they foster good practices of choosing explicit names and tying development work with planning activities for traceability purposes.

gabriel bélanger

Previous post

OSGi-enterprise related open source projects (en)

Next post

Pyxis Technologies joins The Inner Circle partnership program (en)