Evolving Software

I realize that I am not the first to write about unit testing, but there seems to to be an absence of examples dealing with only simple unit testing.  Most all documents deal with unit testing as part of an overall strategy like XP or agile, I don’t really care when you do it as long as you do.

Example Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class ExampleClass {
 
	private String message;
 
	public String getMessage() {
		return this.message;
	}
 
	public void setMessage(String message) {
		this.message = message;
	}
 
	public String operation() {
		StringBuffer buf = new StringBuffer();
		if(message.length() > 10) {
			buf.append(message.hashCode());
		} else {
			buf.append(doubleMessage());
		}
 
		return buf.toString();
	}
 
	private String doubleMessage() {
		return message + message;
	}
 
}

Now this is a stupid class that doesn’t really do anything but since we’ve written it we need to make sure that it works.

First we start with a new test class:

1
2
3
public class ExampleClassTest extends TestCase {
 
}

Of course this class doesn’t actually do anything, but it does show us that it is the Test for ExampleClass based on its name, and that it extends TestCase. Now lets add a test method:

1
2
3
4
5
6
7
8
9
10
public class ExampleClassTest extends TestCase {
 
	public void testMessageStoring() throws Exception {
		ExampleClass example = new ExampleClass();
		example.setMessage('test');
 
		assertEquals('test', example.getMessage());
	}
 
}

As you can see all we are doing is invoking a method on the class and asserting that it responds in an appropriate way, in this case when I set a string that should be available via the get method.  All tests are of the format ‘public void test
() throws Exception { }’,  and junit will be able to locate this test method and run it.  But this test isn’t very comprehensive because it only executes 10 out ot the possible 45 instructions in our class, so we will need to do more testing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ExampleClassTest extends TestCase {
 
	public void testMessageStoring() throws Exception {
		ExampleClass example = new ExampleClass();
		example.setMessage('test');
 
		assertEquals('test', example.getMessage());
	}
 
	public void testClassOperation() throws Exception {
		ExampleClass example = new ExampleClass();
		example.setMessage('test');
 
		assertEquals('testtest', example.operation());
	}
 
}

Here we’ve added a method that tests the operation method of our class, but we know there are two paths inside the operation method and we aren’t exercising 100% of the class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ExampleClassTest extends TestCase {
 
	public void testMessageStoring() throws Exception {
		ExampleClass example = new ExampleClass();
		example.setMessage('test');
 
		assertEquals('test', example.getMessage());
	}
 
	public void testClassOperation() throws Exception {
		ExampleClass example = new ExampleClass();
		example.setMessage('test');
 
		assertEquals('testtest', example.operation());
	}
 
	public void testClassOperationLongMessage() throws Exception {
		ExampleClass example = new ExampleClass();
		example.setMessage('testalongermessage');
 
		assertEquals('-1184182769', example.operation());
	}
 
}

Now we have a test that covers 100% of the instructions in the our class. Now I know that this is a trivial example but unit testing you code shouldn’t be much harder than this, if it is then it is probably a good sign that the complexity of your class has grown beyond what it should be.

Categories: Software Engineering

Leave a Reply