Archive

Archive for April, 2010

Detail formatters to the Rescue!

April 21st, 2010

#toString methods are a powerful debugging tool.

In the Eclipse debugger, the output of #toString is shown in the detail pane of the variables view. It is often useful to adapt the #toString method of your classes to display particular debugging information.

If you are debugging third-party code though, you cannot change their #toString method—bummer! The same applies to objects that belong to the Java API. Exception for example do not print their stack trace, which would be a most useful information when stepping through a catch block.

Detail formatters to the rescue!

Open preference and goto Java > Debug > Detail Formatters and add a new custom formatter for java.lang.Throwable with the following code snippet

java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
this.printStackTrace(new java.io.PrintStream(baos));
return baos.toString();

Now, exceptions will print their stack trace!

public static void main(String[] args) {
    try {
        Arrays.asList().iterator().next();
    }
    catch (Exception ex) {
        System.exit(-1); // Halt here
    }
}

To verify, set a breakpoint in the catch above clause and view ex in the variable view…

Happy hacking!

 

NB: as you can see, there is some code that you are allowed to change and some code that you cannot touch—at least not unless magic tool support is provided. Not all programming languages are like this. There are more dynamic languages, as eg Ruby and Smalltalk, that allow you as a programmer to touch any code, both yours and other, and even to change any object at runtime. The reason static languages like Java do not allow this is because they want to enforce the Curry-Howard correspondence (a mathematical notion of security that cannot cope with dynamic changes) of the type system, but alas they do so at the cost of testability. I won’t say that Java is a Toyota … it is more like a Ford Model-T built when programmers did not yet care about testability.

akuhn Eclipse, Testability

Design for Testability

April 20th, 2010

A car that cannot be tested is a Toyota. We all know that a car needs wheels and a motor to drive. However when engineers build a car they do not just include the bare functionality, they’ll include certain features just for the purpose of testability. Being able to test all functionality is a feature in itself and must not be omitted.

When designing classes it is just the same: some API features are just there for the purpose of testability. It is good design and not an ugly hack if you include certain features just for the purpose of testability!

Let’s consider a Dice class

public interface Dice {
    public int roll();
}

This dice rolls random numbers only. Toyota might consider this a feature-complete dice. We know better. A random dice cannot be used to test software!

Rather we should implement the Dice class as follows

public interface Dice {
    public int roll();
    public void stage(int... n);
}

So then what if we implement two subclasses RandomDice and ScriptableDice and add #stage to the scriptable dice? This won’t work since we want use the same code for both playing an actual game of Ludo and for testing the game. In particular if you’re using a Dependency Injection framework such as Spring or Guice, as it common practice these days, it is a necessity to have a common superclass that works for all setups! Hence, the #stage must be in the superclass. The implementation of RandomDice will throw an UnsupportedOperation exception with the message for testing only; the scriptable dice, of course, will script it self with staged results.

It is good practice though to document code that is used for testing only. We can either do this with a comment or with an annotation. It is preferable to use an annotation since annotations are machine readable while comments are not.

Thus we define

public @interface ForTestingOnly {  }

And rewrite the Dice class as follows

public interface Dice {
    public int roll();
    @ForTestingOnly public void stage(int... n);
}

Now we got a testable and well-documented dice class.

Happy hacking!

akuhn Testability