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();
}

No comments: