Mockito + JUnit Tutorial

What is Mockito?

Mockito is Java based mocking framework for unit testing in Behavior Driven Development (BDD). Which provide way to test functionality of isolated classes without required dependencies like database connection, properties file read or services.

How Mockito Works?

Mockito API use java reflection to mock interfaces so that dummy functionality can be added for unit testing. Mock objects are nothing but proxy for actual implementations where returns a dummy data corresponding to some dummy inputs passed to it.

Benefits of Mockito?

  • Annotation Support: Supports creating mocks using annotations.
  • No Handwriting: No need to write mock objects by own.
  • Return value support: Supports return values.
  • Exception support: Supports exceptions.
  • Order check support: Supports check on order of method calls.
  • Refactoring Safe: Renaming interface method names or reordering parameters will not break the test code as Mocks are created at run time.

Behavior Driven Development (BDD)

Behavior Driven Development (BDD) is current mythology for Agile projects which combines general techniques and principles of Test Driven Development (TDD) and provide developers a new way for doing unit testing. In BDD acceptance criteria for test cases defined as :

Given [initial context], when [event occurs], then [ensure some outcomes].

Behavior Driven Script Development

  • Specify the behavior looking at the system from the outside.
  • Collaborate and come up with a good and clear set of Acceptance Criteria.

Expected Functionality :

The customer should be able to withdraw INR 5000 money from his account.

  1. Given the account has balance of INR 10000.
  2. When the customer requests INR 5000.
  3. Then the account is debited by INR 5000.                 

Expected Behavior Driven Test:

It is an approach to behavior driven testing. Work towards the big picture by considering all possible test cases:

  1. Given the account is in credit.
  2. And the dispenser contains cash.
  3. When the customer requests cash.
  4. Then ensure the account is debited.
  5. And ensure cash is dispensed

You will understand BDD scenarios in depth when you will go with calculator example.

Configure Mockito In Project

<dependencies>
            <!—JUnit 4->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.10</version>
			<scope>test</scope>
		</dependency>
		<!-- Mockito Configuration-->
		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-all</artifactId>
			<version>2.0.2-beta</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.hamcrest</groupId>
			<artifactId>hamcrest-core</artifactId>
			<version>1.2.1</version>
			<scope>test</scope>
		</dependency>
		<!-- End Mockito Configuration -->
	</dependencies>

Mock Vs Spy

Mockito provide way to test isolated classes by two ways:

Mock : an object with the ability to have a programmed expected behavior and  verify the interactions occurring in its lifetime.

Spy: A mock object created as a proxy to an existing real object, some methods can be stubbed, while the un- stubbed ones are forwarded to the covered object. Spy generally uses to unit test some methods which are not depend on other classes.

Ways to Create Mock Object

There are two ways create mock object by Mockito Framework:

  1. Mock Object by Annotation
  2. Mock Object by mock method.

As we know we use Mockito unit testing when backend/database/services are not ready and still need to test application classes.

Mockito Annotations

AnnotationDescription
@MockCreate Mock of given type
@SpyCreate spy of given object
@CaptorCreate Argument captor of given object.
@InjectMockCreate an object of given type and inject mock and spies in existing test.

Here in below calculator example where functionality of calculator operations are not implemented yet but we know what are parameters from CalculatorService interface. Here in below example will create mock object of  CalculatorService and add behavior to mock by using stub object.  We will go step by step mock based behaviors testing.

You will get all dependent classes on Mock First Example.

Mock Object By Annotation

Mockito provide annotation to minimize repetitive mock creation code and make it more readable.

  • @RunWith(MockitoJUnitRunner.class).
  • Use @Mock annotation to create mock object of classes or interfaces.
  • Use @InjectMock annotation to create and inject the mock object for @Spy and @Mock.

In below you will see how to create mock object by annotation. Here Creating Mock object of CalculatorService and Injecting same in MathUtility Class.

For Example:

Mockito Mock Object by Annotation
Mockito: Create Mock Object by Annotation

Mock Object By mock method

  • A mock object can be created with static method mock .

In below you will see how to create mock object by mock method. Here creating Mock object of CalculatorService and Injecting same in MathUtility Class manually by method setCalculatorService().

For Example:

Create Mock Object by mock method
Mockito : Create Mock Object my static mock method

Note : Mockito almost all methods are static better use static import to make code clean. As I have used in above example.

import static org.mockito.Mockito.*;

Mock First Example

Here we are using static mock method to mock CalculatorService object and applying behavior to mock object by stub parameters and return type. In this example you will understand how Behavior Driven Development (BDD) works.

Mock Object :

  • calcService = mock(CalculatorService.class); [Given]

Add Behavior to Mock:

Here we are adding some behavior to mock object as below:

If call add method call [When] stub values 10.0 and 20.0  [Then]  return result as 30.0

when(calcService.add(10.0, 20.0)).thenReturn(30.00);

If call add method call [When] stub values 10.0 and 20.0 [Then] return result as 30.0 same

when(calcService.subtract(20.0, 10.0)).thenReturn(10.00);

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import static org.mockito.Mockito.*;

public class MathUtilityTesterAlt {

	private MathUtility mathUtility;
	private CalculatorService calcService;

	@Before
	public void setUp() {
		mathUtility = new MathUtility();
		// create mock of interface
		calcService = mock(CalculatorService.class);
		mathUtility.setCalculatorService(calcService);
	}

	@Test
	public void addSubstractTest() {
		// add behavior to mock object
		when(calcService.add(10.0, 20.0)).thenReturn(30.00);
		when(calcService.subtract(20.0, 10.0)).thenReturn(10.00);

		Assert.assertEquals(mathUtility.add(10.0, 20.0), 30.0, 0);
		Assert.assertEquals(mathUtility.subtract(20.0, 10.0), 10.0, 0.0);
	}
}

In above example will return successful test result because calling add and subtract method with same values and expecting same result as we added behavior to mock object.

If you noticed in previous Assert.assertEquals() statement we are testing mathUtility class add and subtract methods. MathUtility class is dependent on CalculatorService which is not implemented yet that’s why using mock object.

In below MathUtility class is consuming method of CalcultorService interface.

public class MathUtility {
	private CalculatorService calcService;

	   public void setCalculatorService(CalculatorService calcService){
	      this.calcService = calcService;
	   }

	   public double add(double param1, double param2){
	      return calcService.add(param1, param2);
	   }

	   public double subtract(double param1, double param2){
	      return calcService.subtract(param1, param2);
	   }

	   public double multiply(double param1, double param2){
	      return calcService.multiply(param1, param2);
	   }

	   public double divide(double param1, double param2){
	      return calcService.divide(param1, param2);
	   }
}

CalculatorService interface methods which need to test.

public interface CalculatorService {
	public double add(double param1, double param2);
	public double subtract(double param1, double param2);
	public double multiply(double param1, double param2);
	public double divide(double param1, double param2);
}

Calculator Class which implementing CalculatorService interface methods but implementation is not ready yet. If we will do unit testing on that Calculator class will throw UnsupportedOperationException.

public class Calculator implements CalculatorService {

	public double add(double param1, double param2) {
		throw new UnsupportedOperationException("Method not implemented yet!");
	}
	public double subtract(double param1, double param2) {
		throw new UnsupportedOperationException("Method not implemented yet!");
	}
	public double multiply(double param1, double param2) {
		throw new UnsupportedOperationException("Method not implemented yet!");
	}
	public double divide(double param1, double param2) {
		throw new UnsupportedOperationException("Method not implemented yet!");
	}
}

Now execute above program on eclipse and see response. You will get successful Result.

Mockito Junit Test Example

You can also run above test cases by using TestRunner.

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class MockitoTestRunner {

	public static void main(String[] args) {
		 Result result = JUnitCore.runClasses(MathUtilityTester.class);

	      for (Failure failure : result.getFailures()) {
	         System.out.println(failure.toString());
	      }
	      System.out.println(result.wasSuccessful());
	}
}

Here i try to explain about the create mock object, apply behavior on mock by stub object and execution of test cases on mock.

Verify Test Counts

Some times we need to test in complete execution how many time particular method got executed. Mockito provide some verify api’s to verify calls on mock objects.

@Test
	public void verifyCountTest() {
		when(calcService.add(10.0, 20.0)).thenReturn(30.00);
		when(calcService.subtract(20.0, 10.0)).thenReturn(10.00);
		when(calcService.subtract(30.0, 20.0)).thenReturn(10.00);

		// Add two time
		Assert.assertEquals(mathUtility.add(10.0, 20.0), 30.0, 0);
		Assert.assertEquals(mathUtility.add(10.0, 20.0), 30.0, 0);
		// Substract 3 time
		Assert.assertEquals(mathUtility.subtract(20.0, 10.0), 10.0, 0.0);
		Assert.assertEquals(mathUtility.subtract(20.0, 10.0), 10.0, 0.0);
		Assert.assertEquals(mathUtility.subtract(20.0, 10.0), 10.0, 0.0);

		Assert.assertEquals(mathUtility.subtract(30.0, 20.0), 10.0, 0.0);

		// check if add function is called two times
		verify(calcService, times(2)).add(10.0, 20.0);

		// check if substract function is called two times
		verify(calcService, times(3)).subtract(20.0, 10.0);

		// default call count is 1
		verify(calcService).subtract(30.0, 20.0);

		// verify that method multiply was never called on a mock
		verify(calcService, never()).multiply(10.0, 20.0);

		// check a minimum 1 call count
		verify(calcService, atLeastOnce()).subtract(20.0, 10.0);

		// check if add function is called minimum 2 times
		verify(calcService, atLeast(2)).add(10.0, 20.0);

		// check if add function is called maximum 3 times
		verify(calcService, atMost(3)).subtract(20.0, 10.0);
	}

Verify Timeout

Some times we need to test in complete execution time and purformance prospect API is responding on given time benchmark or not. Mockito provide some verify api’s to verify time of API’s.

@Test
	public void verifyTimeout() {
		when(calcService.add(10.0, 20.0)).thenReturn(30.00);
		when(calcService.subtract(20.0, 10.0)).thenReturn(10.00);

		Assert.assertEquals(mathUtility.add(10.0, 20.0), 30.0, 0);
		Assert.assertEquals(mathUtility.subtract(20.0, 10.0), 10.0, 0.0);

		// verify call to add method to be completed within 200 ms
		verify(calcService, timeout(500)).add(10.0, 20.0);

		// invocation count can be added to ensure multiplication invocations
		// can be checked within given timeframe
		verify(calcService, timeout(100).times(1)).subtract(20.0, 10.0);
	}

Above verify Mockito API’s are self explanatory by name . You can see compete list of verify API in below table.

MethodDescription
times(int expectedNumberOfInvocations)Called exactly n time (By default 1)
never()Never called
atLeastOnce()Called atleast once
atLeast(int minNumberOfInvocations)Called atleast n time
atMost(int maxNumberOfInvocation)Called at most n times
Only()The only method called on a mock
Timeout(int milliseconds)Interacted in specified time range

Verify Order of API execution

Mockito provide InOrder class to verify execution order of API’s. By verify method on InOrder class we can check sequence execution of API’s.

@Test
	public void verifyOrderTest() {
		when(calcService.add(10.0, 20.0)).thenReturn(30.00);
		when(calcService.subtract(20.0, 10.0)).thenReturn(10.00);
		when(calcService.subtract(30.0, 20.0)).thenReturn(10.00);

		Assert.assertEquals(mathUtility.add(10.0, 20.0), 30.0, 0);
		Assert.assertEquals(mathUtility.subtract(30.0, 20.0), 10.0, 0.0);
		Assert.assertEquals(mathUtility.subtract(20.0, 10.0), 10.0, 0.0);

		// create an inOrder verifier for a single mock
		InOrder inOrder = inOrder(calcService);

		inOrder.verify(calcService).add(10.0, 20.0);
		inOrder.verify(calcService).subtract(30.0, 20.0);
		inOrder.verify(calcService).subtract(20.0, 10.0);

	}

Stubbing a Exception

When need to validate exception on particular test . Mockito provide couple of API’s as given below by doThrow to verify exceptions. You can know more of these API’s from below Table.

@Test(expected = RuntimeException.class)
	public void exceptionTest() {
		// add the behavior to throw exception
		doThrow(new RuntimeException("Devision of 0 is not sported.")).when(calcService).divide(0.0, 20.0);

		Assert.assertEquals(mathUtility.divide(0.0, 20.0), 0.0, 0);
	}
MethodDescription
thenReturn(T valueToBeReturned)Returns given value.
thenThrow(Throwable toBeThrown)
thenThrow(Class
toBeThrown)
Throws given exceptions.
then(Answer answer)
thenAnswer(Answer answer)
Uses user created code for testing.
thenCallRealmethod()Calls real method when working
with partial
mock/spy

Stubbing with Custom Answer

The custom answer code is use when tested code is too complicated and should be re-factored. Mockito contains  a generic Answer interface allowing the implementation of callback method  and providing access to invocation parameters, called method and mock instance from InvocationMock object.

@Test
	public void testCallback() {

		// add the behavior to add numbers
		when(calcService.add(20.0, 60.0)).thenAnswer(new Answer<Double>() {

		public Double answer(InvocationOnMock invocation) throws Throwable {
		//retrieve documents pass to mock
		Object[] args = invocation.getArguments();
                //get mock Object
		Object mock = invocation.getMock();
                //return response
		return 80.0;
			}
		});

		// test the add functionality
		Assert.assertEquals(mathUtility.add(20.0, 60.0), 80.0, 0);
	}

Resetting Mock Object

reset(T MockObject) is use to reset mock to forget previous behavior and interactions. Try to avoid use of reset mock method instead of use small test methods for testing. Generally reset mock use in some rare case like use mock as bean in an IoC container.

@Test
	public void testReset() {
		// add the behavior to add numbers
		when(calcService.add(20.0, 10.0)).thenReturn(30.0);

		// test the add functionality
		Assert.assertEquals(mathUtility.add(20.0, 10.0), 30.0, 0);

		// reset the mock
		reset(calcService);

		// add the new behavior to add numbers
		when(calcService.add(20.0, 30.0)).thenReturn(50.0);

		// test the add functionality after resetting the mock
		Assert.assertEquals(mathUtility.add(20.0, 30.0), 50.0, 0);
	}

Mock Test on Real Object (SPY)

spy(T actualObject) use to test mock on actual object. This spy() method is use test those methods which are not depend on other dependencies and implemented. For example done below change in Calculator class

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import static org.mockito.Mockito.*;

public class MathUtilityTesterSpy {

	private MathUtility mathUtility;
	private CalculatorService calcService;

	@Before
	public void setUp() {
		mathUtility = new MathUtility();
		Calculator calculator = new Calculator();
		//Use spy to run test on actual object
	        calcService = spy(calculator);
		mathUtility.setCalculatorService(calcService);
	}
	 @Test
	   public void testAdd(){
          //perform operation on actual calculator
	      Assert.assertEquals(mathUtility.add(20.0, 10.0),30.0,0);
	   }
}

Implemented one method add which is returning some of two param.

public class Calculator implements CalculatorService {

	public double add(double param1, double param2) {
		//throw new UnsupportedOperationException("Method not implemented yet!");
		return param1+param2;
	}

	public double subtract(double param1, double param2) {
		throw new UnsupportedOperationException("Method not implemented yet!");
	}

	public double multiply(double param1, double param2) {
		throw new UnsupportedOperationException("Method not implemented yet!");
	}

	public double divide(double param1, double param2) {
		throw new UnsupportedOperationException("Method not implemented yet!");
	}

}

Change Mock Default Return Value

Default AnswerDescription
RETURNS_DEFAULTSReturns a default "empty" value (e.g.,
null, 0, false, empty collection) - used by
default.
RETURNS_SMART_NULLSCreates a spy of a given object.
RETURN_MOCKSReturns a default "empty" value, but a
mock instead of null.
RETURNS_DEEP_STUBSAllows for a simple deep stubbing (e.g.,
Given(ourMock.getObject().getValue()).
willReturn(s))
CALLS_REAL_METHODCall a real method of spied object

Conclusion

Here we try two cover all possible cases to use Mockito with Junit with examples. Main tocpics covered as below:

  • Introduction and benefits of Mockito.
  • Ways to create Mock object for Junit Testing by mock method and annotations.
  • Ways to create stub objects for testing on mock and real object(SPY).
  • Verify test cases for timeout, counts and sequence of execution.
  • Mockito to handle exceptionable conditions with data.
  • Create Custom Answers for testing etc.

References

http://blog.solidsoft.info/mockito-docs/

http://blog.solidsoft.info/beyond-the-mockito-refcard/.

https://dzone.com/refcardz/mockito?chapter=9

https://www.tutorialspoint.com/mockito/

Advertisements

This site uses Akismet to reduce spam. Learn how your comment data is processed.

“Learn From Others Experience"

%d bloggers like this: