DEV Community

Nipun Arora
Nipun Arora

Posted on

Mockito Tutorial Using Mockito for Java Unit Testing

References:

As I returned back to Java programming, I had to revise my concepts of Junit testing and Mockito. The following is a refresher with quick mockito basics for anyone who wishes to go through them.

Note: Keep in mind the current version is as and when I am learning mockito myself

What is a Mock?

A Mock is a Proxy based instance which routes all calls to a mocking library. When mocking a class the mock creates a instance of the class. Mock allows us to have stubs, which allow the developer to specify the response for any method invoked on the Mock. The default when the mocked invocation has not been stubbed is to return null.

At a high level we divide mocking in the following broad steps

Option 1:
Basic self-contained test mock initialization

//Creating a mock Object of the given class
<ClassName> mockObj = Mockito.mock(<ClassName>.class);
//example
OrderDao mockOrderDao = Mockito.mock(OrderDao.class);

Option 2:
Using @Mock annotation

@Mock
AddService addService;

@BeforeEach
public void setup() {
  //initMocks works with @Mock, @Spy, @Captor, or @InjectMocks annotated objects
  MockitoAnnotations.initMocks(this);
}

@Test
public void testCalc() {
    calcService = new CalcService(addService);
    int num1 = 11; int num2 = 12; int expected = 23;
    when(addService.add(num1, num2)).thenReturn(expected);
    int actual = calcService.calc(num1, num2);
    assertEquals(expected, actual);
}

Option 3:

Stubbing

Stubbing provides capability to define how method calls behave using a when/then pattern. Calling Mockito.when(), returns OngoingStub<T>, specifying how the invocation behaves using the following alternatives:

  • thenReturn():

    Returns value based on the return type of the operation being stubbed

    List<OrderSummary> orderSummaryFixtureList = //Add fixture data
    
    //the following two lines can ideally be compressed into a single call
    OngoingStub<List<OrderSummary>> invocationStub = Mockito.when(mockOrderService.getOrderSummary(customerID)); 
    invocationStub.thenReturn(orderSummaryListFixture);
    
    //Simple invocation
    Mockito.when(mockOrderService.getOrderSummary(customerID)).thenReturn(orderSummaryListFixture);
    
  • thenThrow():
    Test exceptions, which the stub throws

    Mockito.when(...).thenThrow(new OrderServiceException("Test Error"));
    

    Void Methods

    • Mocking void methods do not work with the OngoingStub
    • Mockito.doThrow() returns the Stubber class

      //verbose example of using stubber
      Stubber stubber = Mockito.doThrow(newOrderServiceException("Test error reason"))
      stubber.when(mockOrderService.processOrder(orderFixture));
      
      //compact example of using stubber
      Mockito.doThrow(...).when(mockOrderService.processOrder(orderFixture));
      
  • thenCallRealMethod():
    Sometimes it may be useful to delegate the call to a real method in this scenario mockito allows you to call the actual real method instead. The following is an example of how to delegate the call to the real method instead of the stubbed one.

    Mockito.when(mockObject.targetMethod()).thenCallRealMethod();
    
  • thenAnswer()

    Answering allows you to provide a means to conditionally respond based on mock operation parameters

    Mockito.when(mockObject.targetMethod(Mockito.any(String.class))).thenAnswer(new Answer() {
        Object answer(InvocationOnMock invocation){
            ...
        }
    });
    

Verification

Mockito framework keeps track of all the method calls and their parameters to the mock object. Mockito verify() method on the mock object verifies that a method is called with certain parameters. We can also specify the number of invocation logic, such as the exact number of times, at least specified number of times, less than the specified number of times, etc. We can use VerificationModeFactory for number of invocation times logic. Mockito verify() method checks that a method is called with the right parameters. It does not check the result of a method call like assert method.

Verifying that the mock objects was called, with the specific expected interaction

Mockito.verify(mockOrderDao).findOrdersByCustomer(CUSTOMER_ID)

Verification Mode allows extra verification of the operation

  • times(n)
  • atLeastOnce()
  • atLeans(n)
  • atMost(n)
  • never()

Verifying no interactions globally

  • Mockito.verify().zeroInteractions()
  • Mockito.verify().noMoreInteractions()

Example:

Mockito.verify(mockOrderService, VerificationSettings.times(2)).method

Advanced Mockito Concepts

Argument Matchers

When you want to stub a function with a specific type of argument you can use argument matchers to generalize return values, for instance

Mockito.when(mockOrderDao.findByCustomerId(Matchers.anyString())).thenReturn(orderEntityListFixture);

If any argument is explicit, all of them must be explicit, in the example below both matchers are either explicit or generic.

Mockito.when(mockOrderDao.findByStateAndRegion(Matchers.eq("IL"), Matchers.anyString())).thenReturn(orderEntityListFixture);

Matchers

Matchers.eq(..)

The following is a list of matchers for type of object (i.e. match by class).

Matchers.anyInt(..) //any integer
Matchers.anyDouble(...) //any double
(String)Matchers.any() // typecasted any to string
Matchers.any(<T class>) //typecasted any Template class
(Set<String>)Matchers.anySet() // ??
Matchers.anySetOf(String.class) // ??
  • String Matchers
  • Reference Equality and Reflection

Stubbing Consecutive Calls

Handy for testing logic that needs to be resilient when error occurs:

  1. Looping logic that either short-circuts or continues on exception
  2. Retry logic when errors are encountered

Stub multiple responses in order one after the other for giving consecutive returns.

The following is an example of first throwing an exception and then returning a value. This is an example of successful execution after retries.
Mockito.when(...).thenThrow(...).thenReturn(...)

The following is an example where there are multiple failures, so we test throwing multiple exceptions in multiple calls.
Mockito.when(...).thenThrow(...).thenThrow(...)

Inorder verification

inOrderVerifier = Mockito.inOrder(MockOfferService, MockTaxService);
//Verify that the following two are called, and are called in the correct order
inOrderVerifier.verify(MockOfferService)....
inOrderVerify.verify(MockTaxService)...

Argument Campturing

Retrieve the object passed to a mock from within the testing code to verify that the correct arguments were passed

ArgumentCaptor<Obj> orderEntityCaptor = ArgumentCaptor.forClass(<ClassName>.class);

//Now to actually capture the variables
Mockito.verify(...).function(orderEntityCaptor.capture());

//Get the Captured Value
Object obj = orderEntityCaptor.getValue();

Spies

Compared to mocking, a spy wraps an actual instance of the class within a proxy implementation. The default behavior of the spy is to call the real method when no stubbing has been specified.

Partial Mocking (TBD)

When partial mocking keep the following things in mind:

  • Can't mock private methods
  • Can't mock final mehtods
  • Set the state appropriately

When stubbing a spy, the initial call is routed to the real method, this can result in unexpected exceptions

List<String> liveList = new LinkedList<String>();
List<String> spyList = Mockito.spy(liveList);

//This will give an exception as it will trigger an empty list because spy first routes call to real method
Mockito.when(spyList.get(0)).thenReturn("A string result");

// The following is a work around
spyList.add("dummy value");
Mockito.when(spyList.get(0)).thenReturn("A string result");

PowerMock

Mockito does not have

  • Ability to mock static operations
  • Ability to mock final/private

PowerMock provides an extension to Mockito. Uses a custom classloader, and byte code manipulation.

Mocking static functions using PowerMock

//Initialize using the following to annotate the test class
@RunWith(PowerMockRunner.class)
@PrepareForTest(value={<ClassName>.class})
public class AbcTest{

}
//stubbing static method using powermock
PowerMockito.mockStatic(<ClassName>.class)
PowerMockito.when(Class.method(Matchers...)).thenReturn(...);

//verifying static method using powermock
PowerMockito.verifyStatic();
Obj argument = ArgumentCaptor.forClass(...).getValue;
// follow up with assertions to verify...

Replace Object Instantiation

Calls to "new" operator can be replaced by stubbed results.

// Call zero parameter constructor by class name
// Use reflection or specific constructor
// Specify specific constructor using a string value
PowerMockito.whenNew(...)

whenNew() returns PowerMock's version of OngoingStub<T>

  • ConstructorExpectationSetup<T>
  • WithOrWithoutExpectedArguments<T>

Note: You need to specify the class under test and not the class being instantiated
@PrepareForTest(ClassUnderTest.class)

Example:

OrderCompletionAudit auditFixture = new OrderCompletionAudit();
PowerMockito.whenNew(OrderCompletionAudit.class).withNoArguments().thenReturn(auditFixture);
Assert.assertEquals(ORDER_NO, auditFixture.getOrderNumber());
Assert.assertNotNull(auditFixture.getCompletionDate());

Stubbing Final & Private Methods

  • Stubbing final operations are straightforward and nothing else expected
  • Stubbing private methods requires - pass the mock and a java reflection method object into when method & WithOrWithoutExpectedArguments are returned
PowerMockito.verifyPrivate(...) -> returns PrivateMethodVerification, which allows you to verify the private calls

PrivateMethodVerification.invoke(...)

PrivateMethodVerification pmVerification = Mockito.verifyPrivate(mockOrderService);
//Use either this
pmVerification.invoke(method).withArguments(item1, order);

//Or this
pmVerification.invoke("calculateDiscount", item1, order);

Whitebox Test Utility Class (TBD)

Wrapper around java reflection api, but geared towards testing

  • good for testing private methods
  • removes exception handling- the test will fail if encountered during whitebox method calls

Fixture Management

  • Fixture state initialization is performed for each test
    • Instantiate objects to pass into methods
    • Declare mock stubs/initialize objects they return
    • Insert data in rdbms for data access tests
    • Create files

TearDown

  • Clean up files created, data added to persistent storage

Managing Object Fixtures

Only do minimum amount of object fixtures.

Latest comments (0)