Donnerstag, 18. Juni 2009

Partially mocking the class under test

When writing a class it sometimes happens that you have to write a method which invokes methods of the same instance. I was wondering how to test those methods in isolation. Here is an abstract example demonstrating the problem: Class XYZ
  • method doThisIfCase1OrThatOtherwise
  • method doThis
  • method doThat
Testing doThis and doThat should not be a problem. But testing doThisIfCase1OrThatOtherwise without testing doThis and doThat again seemed impossible to me. Of course it would be possible to extract doThis and doThat into a separate class and then mock this class when testing doThisIfCase1OrThatOtherwise. But there are cases doing this smells a bit like over engineering. In cases I don't know what to do I ask Misko my test and clean code oracle. As always he provided me with a solution: Override the methods doThis and doThat and assert that they get called. This is an example from my "real" world: The class under test:
...
public void openAndCreateIfNotExists() throws IOException {
if (!destinationClassPathFile.exists()) {
 createEmptyClassPathFile();
} else {
 openExistingClassPathFile();
}
}

void createEmptyClassPathFile() {
eclipseClassPathDocument = DocumentHelper.createDocument();
eclipseClassPathDocument.addElement("classpath");
}

void openExistingClassPathFile() throws IOException {
SAXReader reader = new SAXReader();
try {
 eclipseClassPathDocument = reader.read(destinationClassPathFile);
} catch (DocumentException e) {
 throw new IOException("Invalid class path file " + destinationClassPathFile.getCanonicalPath(), e);
}
}
...
The test:
@Test
public void testOpenAndCreateIfNotExistsCreates() throws IOException {
File file = new File("src-test/testOpenAndCreateIfNotExistsCreates.testFile");
if (file.exists())
 file.delete();
file.deleteOnExit();
assertFalse(file.exists());
final StringBuilder stringBuilder = new StringBuilder();
EclipseClassPathManipulator eclipseClassPathManipulator = new EclipseClassPathManipulator(file) {
 @Override
 void createEmptyClassPathFile() {
  stringBuilder.append("igotcalled");
 }
};
eclipseClassPathManipulator.openAndCreateIfNotExists();
assertEquals("igotcalled", stringBuilder.toString());
}

@Test
public void testOpenAndCreateIfNotExistsOpens() throws IOException {
final StringBuilder stringBuilder = new StringBuilder();
File file = new File("src-test/testOpenAndCreateIfNotExistsOpens.testFile");
file.createNewFile();
file.deleteOnExit();
assertTrue(file.exists());
EclipseClassPathManipulator eclipseClassPathManipulator = new EclipseClassPathManipulator(file) {
 @Override
 void openExistingClassPathFile() throws IOException {
  stringBuilder.append("igotcalled");
 }
};
eclipseClassPathManipulator.openAndCreateIfNotExists();
assertEquals("igotcalled", stringBuilder.toString());
}

Keine Kommentare:

  © Blogger template 'Morning Drink' by Ourblogtemplates.com 2008

Back to TOP