If you've written Junits in your life, you must be familiar with the Mockito Framework or any other framework and you must've used it to mock a class and define the output of certain method calls at runtime. The main advantage of using a framework like Mockito is that it greatly simplifies the development of tests for classes with external dependencies.
Now, What if I don't use any framework? Will I still be able to mock the behaviours of dependent classes? I'll try to write a unit test for the below piece of code without Mockito and find out.
Here's the code I want to test :
public class IncrementNumber {
public int getIncrementedNumber(int num){
DBConn conn = getConn();
return conn.getValue(num);
}
DBConn getConn(){
return DBConnFactory.establishConnection();
}
}
I want to test the getIncrementedNumber
method in this class but we can see how it's dependent on Database Connection to return the output. We can't establish the connection in test class and make it call the actual Database just to test the behaviour of the method, right? So, How do we mock the behaviour?
We'll use one of the most beautiful property of Java, Polymorphism. Polymorphism allows us to use method overriding. The version of a method that is executed will be determined by the object that is used to invoke it. If an object of a parent class is used to invoke the method, then the version in the parent class will be executed, but if an object of the subclass is used to invoke the method, then the version in the child class will be executed. Are you getting the hint now? That's exactly what we'll profit off from to solve the above problem statement.
We'll create a child class IncrementNumber and override getConn
to return my own mock for DBConn. That looks like this :
public class MockIncrementNumber extends IncrementNumber{
MockDBConn conn;
@Override
DBConn getConn(){
this.conn = new MockDBConn();
return this.conn;
}
}
The MockDBConn class going to capture the argument passed in getValue
and return the output, so that needs to be overridden as well. This is how it looks :
public class MockDBConn extends DBConn{
@Override
public int getValue(int param){
return param + 4;
}
}
Now, with all things in place, The unit test looks like this :
@Test
public void shouldReturnIncrementedValue{
IncrementNumber inc = new MockIncrementNumber();
assert inc.getIncrementedNumber(4) == 8;
}
We've used basic object-oriented principles to solve this problem. We were able to create the child mock classes and override original classes behaviour easily. But, We had to write more code when we went through this route for mocking behaviours. This could be advantageous as well as disadvantageous. It's probably good since mock classes are visible and I don't have to visualize what they're doing or go through their documentation. I don't mean to say we should never use a mocking framework, I am just saying it is a reasonable choice sometimes to not use one. Also, These frameworks are another dependency on your project, and that adds it's own maintainability issues and restricts change. That being said, If it's easier to use a mocking framework, do that. If not, use this approach instead.
Top comments (0)