Software QA FYI - SQAFYI

Design Principles in Test First Programming

By: Erik Meade

Introduction
The purpose of this article is to examine how test first programming produces code which adheres to certain design principles. In particular we will see that test first programming insures that we follow the Open/Closed,LiskovSubstitution Principle and Dependency Inversion principles, introduced to us in 1996 by Robert C. Martin. Here we will revisit the Copy program, which Robert used to demonstrate the Dependency Inversion Principle, only we will do so test first using Kent Beck and Erich Gamma's JUnit , a testing framework for Java.

The Copy program Robert used the Copy program as an example of code rot. The basic Copy program reads from the keyboard and prints to the printer. Enhancing the Copy program so it can also print to the disk results in an if else statement based on type which definitely has a code smell to those of us who understand the Open/Closed Principle. As a reminder the Open/Closed Principle states that we should add new functionality by adding new code, not by editing old code.

Since the entire purpose of the Copy program is to copy, We will focus on writing the test for it first, but how do we write a test for a class that uses two other classes without creating those classes first? Do the simplest thing that could possibly work, create mock objects for the Reader and Writer classes. Now we have enough to implement test first. The MockReader will allow us to hard code what we are going to read, and the MockWriter will expose a field so we can check that it "wrote" the right thing.

import junit.framework.TestCase;
public class CopyTest extends TestCase {
public CopyTest ( String name ) {
super ( name );
}
public void testCopy () {
String testLine = "input";
MockReader reader = new MockReader ( testLine );
MockWriter writer = new MockWriter ();
Copy copy = new Copy ( reader, writer );
copy.copy ();
assertEquals ( testLine , writer.output );
}
}


Compiling this produces a few errors, all related to the fact that none of the classes used exist. Addressing each error in the order they appear results in the following:

class MockReader {
String input;
MockReader ( String input ) {
this.input = input;
}
public String readln () {
String line = input;
input = null;
return line;
}
}
class MockWriter {
String output;
public void writeln ( String line ) {
output = line;
}
}
class Copy {
MockReader reader;
MockWriter writer;
Copy ( MockReader reader , MockWriter writer ) {
this.reader = reader;
this.writer = writer;
}
void copy () {
String line;
while ( ( line = reader.readln () ) != null )
writer.writeln ( line )

Full article...


Other Resource

... to read more articles, visit http://sqa.fyicenter.com/art/

Design Principles in Test First Programming