References:
- Mockito Tutorial JournalDev
- Mockito Tutorialspoint
- Mockito Tutorial JavaCodeHouse
- Dependency Injection
- Reflections
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
- Initiation
- Stubbing
- Verification ## Initialization Reference:
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:
- Looping logic that either short-circuts or continues on exception
- 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.
Top comments (0)