Thursday, December 18, 2008

Preconditions, Postconditions, Invariants : Design by Contract for Java #2

Recently I wrote about how to apply "Design by Contract" with Java. I proposed to use the assert statement of java, in case you do not want to set up some external tools like Contract4J, iContract or Jass. After using the assert statement for a while I would recommend to use your own implementation of assertions instead like this:
public class Assertion {

 /**
  * Precondition.
  * @param condition we expect to be true.
  * @param description repeats the condition or describes it in
  * other words.
  */
 public static void Require(boolean condition, String description) {
     if (!condition) {
         throw new RuntimeException("Precondition: The expectation '" + description + "' is violated");
     }
 }

 /**
  * Precondition.
  * @param objectToBeTested is an object we expect to be not null
  * @param objectName is the name of the variable we test.
  */
 public static void RequireNotNull(Object objectToBeTested,String objectName) {
     if (objectToBeTested == null) {
         throw new RuntimeException("Precondition: The expectation '" + objectName + " is not null' is violated");
     }
 }

 /**
  * Postcondition.
  * @param condition we expect to be true.
  * @param description repeats the condition or describes it in
  * other words.
  */
 public static void Ensure(boolean condition, String description) {
     if (!condition) {
         throw new RuntimeException("Postcondition: The expectation '" + description + "' is violated");
     }
 }

 /**
  * Common condition to be used in the middle of methods
  * @param condition we expect to be true.
  * @param description repeats the condition or describes it in
  * other words.
  */
 public static void Check(boolean condition, String description) {
     if (!condition) {
         throw new RuntimeException("Condition: The expectation '" + description + "' is violated");
     }
 }
}
Why is the own implementation better than the assert statement?
  1. It does not make sense to switch off the runtime checks of assertions. We use assertions to simplify and avoid the error handling code in our methods. When it is possible to switch of assertions we loose this advantage, because we have to prepare our code to handle situations where the assertions are not checked.
  2. We are not only profiting from assertions during development and testing but also when the software is deployed. Assertions uncover error conditions much clearer and with better error descriptions. The logs in a production system will contain the messages from assertions and will help to find the cause of the problem much faster. If we switch off the assertions the problems will occurring much later and the cause of the problem can only be found with much more effort,
You can find details about "Design by Contract" in the famous book Object-Oriented Software Construction by Bertrand Meyer.

Monday, December 15, 2008

Mocking an object with two interfaces

Currently I spend a lot of time with maintaining 'legacy' java code. That is not really funny :-(. To make the most out of it, I write as much unit tests as possible to gain some more confidence in the code and be prepared for future bugfixes and refactorings. I stumbled over a small problem, when I tried to mock an object which implements two interfaces. My 'system under test'(SUT) class TextManager uses an object which is an IReader and an IWriter at the same time. The object is only handed over once and the TextManager has to cast the IReader object into an IWriter object. The whole design is not really outstanding (to be polite) and I would have implemented it myself a little bit different.
public class TextManager {
   
   private IReader reader;
   
   public void readAndWrite() {
      String text = reader.read();
      text = "*" + text + "*";
      ((IWriter)reader).write(text);
   }
}
I wrote a unit test for the readAndWrite() method and recognized that I can't simply create a jMock object for the IReader/IWriter object. My colleague Henning found a simple an effective solution. In my test package I create a new interface called IReaderWriter which extends IReader and IWriter. Now I can create a mock object for this new interface which is able to work as a test double inside TextManager:
public void testReadAndWrite() {
    
    // Setup
    final IReaderWriter mock = context.mock(IReaderWriter.class);
    TextManager textManager = new TextManager(mock);
    context.checking(new Expectations() {{
        one(mock).read(); will(returnValue("test"));
        one(mock).write("*test*");
    }});
    
    // Exercise
    textManager.readAndWrite();
    
    // Verify
    context.assertIsSatisfied();
}