10.3 Debugging Code

Debugging Code

Debugging code is a topic that people do not find particularly interesting, but it is vital to the software development cycle. Detecting bugs early saves money. It is estimated that software bugs missed at requirements definition stage can cost 5 times more to fix during design, 10 times more to fix during coding, 20 times more to fix during unit testing and 200 times more to fix after the software has been delivered. The first defense against bugs are assertions. Assertions contain Boolean statements that confirm the state of the program at a point in the source code.

Using Assertions in Java

With the release of J2SE 1.4 Assertions were introduced into the Java language. Here is a code example to show assertions in use. The line assert s!=null; is an example of an assertion. We are asserting the state of s at this point in the program code. We are assuming that it is not equal to null. Now assume that the //code here... line represents a set of statements that are called that could potentially affect s. The assertion that we make just checks that s!=null. Now it is not really that useful here, but assume that the //code here could have the negative effect of causing s to be set to null. The assertion statement checks that this is not the case.

public class AssertionTest {

	public static void main(String[] args) {
		String s;
		s = new String("Hello World!");
		//code here...
		//e.g. s=null;
		assert s!=null;		
		//Call something important and pass s

In this program if s does equal null then an exception will occur of the form:

Exception in thread "main" java.lang.AssertionError
	at AssertionTest.main(AssertionTest.java:11)

This will only occur if we have 'turned on' assertions in the virtual machine. We can do this by passing the flag -ea at the command line e.g. java -ea AssertionTest, where AssertionTest is the name of our class. We can also do this by adding -ea to the VM Arguments in the Run Configuration of our Eclipse IDE.

In this section of code we can assume that s exists and can be used safely after we perform the assertion, but importantly it will also help us quickly identify errors in our code.

It is worth mentioning that assertions exist in C++ also, but we do it by calling a standard function void assert(int expression) which only works if we have #define NDEBUG present at the start of our program. Once testing is complete in C++, all we have to do is remove the line #define NDEBUG from our code; in Java, we simply remove the -ea flag from our call to the Virtual Machine. In both cases, assertions do not affect the performance of our release level code.

There are some additional functionality with assertions in Java. For example, we can display a message when an assertion exception occurs.

public static void main(String[] args) {
	assert s!=null : "The String S is Null";		

which results in the following exception when the assertion evaluates to false (i.e. s is null):

Exception in thread "main" java.lang.AssertionError: The String S is Null
	at AssertionTest.main(AssertionTest.java:11)

So, assertions allow for conditional testing of our code, where importantly, we can turn off the checks once we have ensured that the code is working correctly. Assertions can therefore play a valuable role in debugging and designing code, while keeping testing in mind.