Wednesday, January 17, 2018

Implementing mocking with JUNITs

JUNITs are an easy and effective way to unit test your code. However when writing a JUNIT you need to ensure that the scope of test case remains within that class
only and does not go beyond it.
What this means is that say you have a class A which call a method of Class B from within it. Then ur unit test case should be limited to methods of Class A and
should not test method of Class B otherwise the test case will become an integration test. This can be achieved using a Mock framework such as Mockito and this is
where JUNITs become tricky as well.

I was trying to write JUNITs using Mockito for a simple case as mentioned above. Class code below:

Class to be tested:

public Class A {
  public String parseEvent(String line) {
// some business logic
ClassB bObj = new ClassB();
String randomNum = bObj.getRandomNum().toString();
return line.append(randomNum);
  }
}

Junit:

public class ATest {

   @Test
   public void testParseEvent() {
       String inputLine= <some data>;
       String expectedOutput =<some data>;
       
       ClassB bObject = mock(ClassB.class);
       when(bOject.getRandomNum()).thenReturn(2);
       
       Class A aObject = new ClassA();
       String result = aObject.parseEvent(inputLine);
       Assert.assertArrayEquals(expectedOutput.getBytes(),result.getBytes());
       
   }

}

This looked alright to me. I was trying to mock class B's method so as to return a predetermined number and then compare expected and actual output.
However despite trying above and many other approaches I could see that B's method was actually getting called instead of getting mocked.

After a lot of googling found out that the issue was not with Junit or Mocking but with the way Class A was written. Since it was instantiating object of Class B, 
the mock object got lost and acutal instance got called. After refactoring Class A, Junit worked fine. Refactored code below:

public ClassA {

   private ClassB obj=null;

   public ClassA(ClassB obj) {
this.obj=obj;
   }

  public String parseEvent(String line) {
// some business logic
String randomNum = obj.getRandomNum().toString();
return line.append(randomNum);
  }
}

After refactoring Class A's code, in my JUNIT i passed the mocked object of Class B when creating object of Class A. The mocking worked fine and Junit returned 
expected result. 
Happy Ending :) 

No comments:

Post a Comment