Learn Mocking Private, Static and Void methods in Mockito with Examples:
In this series of hands-on Tutorials on Mockito, we had a look at the different types of Mockito Matchers in the last tutorial.
Generally speaking, mocking private and static methods come under the category of unusual mocking.
If the need arises to mock private and static methods/classes, it indicates poorly refactored code and is not really a testable code and is most likely that some legacy code which was not used to be very unit test friendly.
Having said that, there still exists support for Mocking private and static methods by few unit testing frameworks like PowerMockito (and not directly by Mockito).
Mocking “void” methods are common as there might be methods which are essentially not returning anything, like updating a database row (consider it as a PUT operation of a Rest API endpoint which accepts an input and does not return any output).
Mockito provides full support for mocking void methods, which we will see with examples in this article.
Table of Contents:
Powermock – A Brief Introduction
For Mockito, there is no direct support to mock private and static methods. In order to test private methods, you will need to refactor the code to change the access to protected (or package) and you will have to avoid static/final methods.
Mockito, in my opinion intentionally does not provide support for these kinds of mocks, as using these kinds of code constructs are code smells and poorly designed code.
But, there are frameworks which support mocking for private and static methods.
Powermock extends capabilities of other frameworks like EasyMock and Mockito and provides the capability to mock static and private methods.
#1) How: Powermock does this with the help of custom bytecode manipulation in order to support mocking private & static methods, final classes, constructors and so on.
#2) Supported packages: Powermock provides 2 extension APIs – one for Mockito and one for easyMock. For the sake of this article, we are going to write examples with the Mockito extension for power mock.
#3) Syntax: Powermockito has an almost similar syntax as Mockito, except some additional methods for mocking static and private methods.
#4) Powermockito Setup
In order to include the Mockito library in gradle based projects, below are the libraries to be included:
testCompile group: 'org.powermock', name: 'powermock-api-mockito2', version: '1.7.4' testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '1.7.4'
Similar dependencies are available for maven as well.
Powermock-api-mockito2 – The library is required to include Mockito extensions for Powermockito.
Powermock-module-junit4 – Module is required to include PowerMockRunner (which is a custom runner to be used for running tests with PowerMockito).
An important point to note here is that PowerMock does not support Junit5 test runner. Hence the tests need to be written against Junit4 and the tests need to be executed with PowerMockRunner.
To use PowerMockRunner – the test class needs to be annotated with @RunWith(PowerMockRunner.class)
Now let’s discuss, mocking private, static and void methods in detail!
Mocking Private Methods
Mocking private methods, which are called internally from a method under test can be unavoidable at certain times. Using powermockito, this is possible and the verification is done using a new method named ‘verifyPrivate’
Let’s take an Example where method under test calls a private method (which returns a boolean). In order to stub this method to return true/false depending on the test, a stub needs to be set up on this class.
For this Example, the class under test is created as a spy instance with mocking on few interface invocations and private method invocation.
Important points to Mock Private Method:
#1) The test method or test class needs to be annotated with @PrepareForTest(ClassUnderTest). This annotation tells powerMockito to prepare certain classes for testing.
These will be mostly those classes that need to be Bytecode manipulated. Typically for final classes, classes containing private and/or static methods that are required to be mocked during testing.
Example:
@PrepareForTest(PriceCalculator.class)
#2) To setup stub on a private method.
Syntax – when(mock or spy instance, “privateMethodName”).thenReturn(//return value)
Example:
when(priceCalculatorSpy, "isCustomerAnonymous").thenReturn(false);
#3) To verify the stubbed private method.
Syntax – verifyPrivate(mockedInstance).invoke(“privateMethodName”)
Example:
verifyPrivate(priceCalculator).invoke("isCustomerAnonymous");
Complete Test Sample: Continuing the same example from the previous articles, where priceCalculator has some mocked dependencies like itemService, userService etc.
We have created a new method called – calculatePriceWithPrivateMethod, which calls a private method inside the same class and returns whether the customer is anonymous or not.
@Test @PrepareForTest(PriceCalculator.class) public void calculatePriceForAnonymous_witStubbedPrivateMethod_returnsCorrectPrice() throws Exception { // Arrange ItemSku item1 = new ItemSku(); item1.setApplicableDiscount(5.00); item1.setPrice(100.00); double expectedPrice = 90.00; // Setting up stubbed responses using mocks when(priceCalculatorSpy, "isCustomerAnonymous").thenReturn(false); when(mockedItemService.getItemDetails(123)).thenReturn(item1); // Act double actualDiscountedPrice = priceCalculatorSpy.calculatePriceWithPrivateMethod(123); // Assert verifyPrivate(priceCalculator).invoke("isCustomerAnonymous"); assertEquals(expectedPrice, actualDiscountedPrice); }
Mocking Static Methods
Static methods can be mocked in a similar way as we saw for the private methods.
When a method under test, involves using a static method from the same class (or from a different class), we will need to include that class in prepareForTest annotation before the Test (or on the test class).
Important points to Mock Static Methods:
#1) The test method or test class needs to be annotated with @PrepareForTest(ClassUnderTest). Similar to mocking private methods/classes, this is required for static classes too.
#2) One extra step that is required for static methods is – mockStatic(//name of static class)
Example:
mockStatic(DiscountCategoryFinder.class)
#3) To setup stub on a static method, is as good as stubbing any method on any other interface/class mock instances.
For Example: To stub getDiscountCategory() (which returns an enum DiscountCategory with values PREMIUM & GENERAL) static method of DiscountCategoryFinder class, simply stub as follows:
when(DiscountCategoryFinder.getDiscountCategory()).thenReturn(DiscountCategory.PREMIUM);
#4) To verify the mock setup on the final/static method, verifyStatic() method can be used.
Example:
verifyStatic(DiscountCategoryFinder.class, times(1));
Mocking Void Methods
Let’s first try to understand what kind of use cases might involve stubbing void methods:
#1) Method calls for example – that sends an email notification during the process.
For Example: Suppose you change your password for your internet banking account, once the change is successful you receive notification over your email.
This can be thought of as /changePassword as a POST call to Bank API which includes a void method call to send an email notification to the customer.
#2) Another common example of the void method call is updated requests to a DB which take some input and do not return anything.
Stubbing void methods (i.e. the methods that do not return anything, or else throw an exception), can be handled using doNothing(), doThrow() and doAnswer(), doCallRealMethod() functions. It requires the stub to be set up using the above methods as per the test expectations.
Also, please note that all the void method calls are by default mocked to doNothing(). Hence, even if an explicit mock setup is not done on VOID method calls, the default behavior is still to doNothing().
Let’s see Examples for all these functions:
For all the examples, let’s assume, that there are a class StudentScoreUpdates which has a method calculateSumAndStore(). This method calculates the sum of scores (as input) and calls a void method updateScores() on databaseImplementation instance.
public class StudentScoreUpdates { public IDatabase databaseImpl; public StudentScoreUpdates(IDatabase databaseImpl) { this.databaseImpl = databaseImpl; } public void calculateSumAndStore(String studentId, int[] scores) { int total = 0; for(int score : scores) { total = total + score; } // write total to DB databaseImpl.updateScores(studentId, total); } }
We will be writing unit tests for the mock method call with the below examples:
#1) doNothing() – doNothing() is the default behavior for void method calls in Mockito i.e. even if you verify a call on void method (without explicitly setting up a void to doNothing(), the verification will still be successful)
public void calculateSumAndStore_withValidInput_shouldCalculateAndUpdateResultInDb() { // Arrange studentScores = new StudentScoreUpdates(mockDatabase); int[] scores = {60,70,90}; Mockito.doNothing().when(mockDatabase).updateScores(anyString(), anyInt()); // Act studentScores.calculateSumAndStore("student1", scores); // Assert Mockito.verify(mockDatabase, Mockito.times(1)).updateScores(anyString(), anyInt()); }
Other usages along with doNothing()
a) When the void method is called multiple times, and you want to setup different responses for different invocations, like – doNothing() for the first invocation and throw an exception on the next invocation.
For Example: Set up mock like this:
Mockito.doNothing().doThrow(new RuntimeException()).when(mockDatabase).updateScores(anyString(), anyInt());
b) When you want to capture the arguments that the void method was called with, the ArgumentCaptor functionality in Mockito should be used. This gives an added verification of arguments that the method was called with.
Example with ArgumentCaptor:
public void calculateSumAndStore_withValidInput_shouldCalculateAndUpdateResultInDb() { // Arrange studentScores = new StudentScoreUpdates(mockDatabase); int[] scores = {60,70,90}; Mockito.doNothing().when(mockDatabase).updateScores(anyString(), anyInt()); ArgumentCaptor<String> studentIdArgument = ArgumentCaptor.forClass(String.class); // Act studentScores.calculateSumAndStore("Student1", scores); // Assert Mockito.verify(mockDatabase, Mockito.times(1)).updateScores(studentIdArgument.capture(), anyInt()); assertEquals("Student1", studentIdArgument.getValue()); }
#2) doThrow() – This is useful when you simply want to throw an exception when the void method is invoked from the method under test.
For Example:
Mockito.doThrow(newRuntimeException()).when(mockDatabase).updateScores (anyString(), anyInt());
#3) doAnswer() – doAnswer() simply provides an interface to do some custom logic .
E.g. Modifying some value through the passed arguments, returning custom values/data which a normal stub could not have returned especially for void methods.
For the purpose of demonstration – I’ve stubbed the updateScores() void method to return an “answer()” and print the value of one of the arguments that should have been passed when the method should have been called.
Code Example:
@Test public void calculateSumAndStore_withValidInput_shouldCalculateAndUpdateResultInDb() { // Arrange studentScores = new StudentScoreUpdates(mockDatabaseImpl); int[] scores = {60,70,90}; Mockito.doCallRealMethod().when(mockDatabaseImpl).updateScores(anyString(), anyInt()); doAnswer(invocation -> { Object[] args = invocation.getArguments(); Object mock = invocation.getMock(); System.out.println(args[0]); return mock; }).when(mockDatabaseImpl).updateScores(anyString(), anyInt()); // Act studentScores.calculateSumAndStore("Student1", scores); // Assert Mockito.verify(mockDatabaseImpl, Mockito.times(1)).updateScores(anyString(), anyInt()); }
#4) doCallRealMethod() – Partial mocks are similar to stubs (where you can call real methods for some of the methods and stub out the rest).
For void methods, mockito provides a special function called doCallRealMethod() which can be used when you are trying to set up the mock. What this will do, is call the real void method with the actual arguments.
For Example:
Mockito.doCallRealMethod().when(mockDatabaseImpl).updateScores(anyString(), anyInt());
Tips & Tricks
#1) Including multiple static classes in the same test method/class – Using PowerMockito if there is a need to Mock multiple Static of Final classes then the class names in @PrepareForTest annotation can be mentioned as comma separated value as an array (it essentially accepts an array of the class names).
Example:
@PrepareForTest({PriceCalculator.class, DiscountCategoryFinder.class})
As shown in the example above, assume both PriceCalculator and DiscountCategoryFinder are final classes that need to be mocked. Both of these can be mentioned as an array of classes in PrepareForTest annotation and can be stubbed in the test method.
#2) PrepareForTest attribute Positioning – The positioning of this attribute is important with regards to the kind of tests that are included in the Test class.
If all the tests need to use the same final class, then it makes sense to mention this attribute at test class level which simply means that the prepared class will be available to all the Test Methods. As opposed to this, if the annotation is mentioned on the test method, then it will be available only to that particular tests
Conclusion
In this tutorial, we discussed various approaches to mock static, final and void methods.
Though using a lot of static or final methods hinders testability, and still, there is support available for testing/mocking to assist in creating unit tests in order to achieve greater confidence in the code/application even for legacy code which is generally not used to be designed for testability.
For static and final methods, Mockito does not have an out of box support, but libraries like PowerMockito (which heavily inherit a lot of things from Mockito) does provide such support and has to actually perform bytecode manipulation in order to support these features.
Mockito out of the box supports stubbing void methods and provides various methods like doNothing, doAnswer, doThrow, doCallRealMethod etc. and can be used as per the requirement of the test.
Most Frequently asked Mockito Interview Questions are briefed in our next tutorial.