Friday, January 10, 2014

A good design in classes could make Mockito happier

I am having difficulty on executing a unit test that will throw ClassNotFoundException when an error has occurred. But later I found out that this difficulty isn’t come from the limitation of the test framework (Mockito or PowerMock) but it is due to the design problem in my class. I think I should aware of this problem during the development stage but why I only see it during unit test stage? Not only this design is impractical but it also makes the unit test execution even harder. Consider the following scenario, I have initConnection() declared in base class, and this method is invoke from the subclass:
public abstract class ReportService {

 ...
 ...

 protected void initConnection() {
  try {
   ...
   ...

  } 
  catch(HibernateException e) {
   e.printStackTrace();
  } 
  catch (ClassNotFoundException e) {
   e.printStackTrace();
  }
 }
}

public abstract class HibernateReportService<T> extends ReportService {

 ...
 ...

 public void execute() {
  
  try {
   initConnection();

   ...
   ...
  }
  finally {
  }

 ...
}
Assuming I want to verify ClassNotFoundException is thrown when an error has occurred. If I initiate the test execution using following code snippet, this will cause the test failed because the exception has been caught in base class.
 @Test(expected=ClassNotFoundException.class)
 public void testInitConnectionClassNotFoundException() throws Exception {
  ...
  ...
Suddenly, my mind raise up a very interesting question to me, am I doing the thing right? Am I coding the right thing? According to the best practices, I should not catch the exception in base class whereas I should escalate to the subclasses to handle the exception. By following this design, changes were made on the base code, initConnection() will no longer catching any exception:
 protected void initConnection() throws ClassNotFoundException {
  ...
 }
When I execute the unit test code above, the test was finally passed. Something has been clear in my mind now, during Whitebox testing, the test is not to check whether the exception has been handles properly but to verify what will be the behavior if an exception has been thrown. Put in other words, exception must throw during Whitebox testing. When handover to test team, then only tester will need to verify those exceptions being handles properly through a series of black box testing, not during Whitebox testing.

No comments: