Creating new objects directly within a method often violates dependency injection principles. Ideally, refactoring to adhere to clean code architecture is the preferred solution.
However, if refactoring isn't immediately feasible, the following example demonstrates how to mock object creation (constructors) in Java using Mockito.
The complete code for this project is available on my GitHub repository (getButton) #text=(GitHub) #icon=(share) #color=(#000000)
TransactionService class
The upiPayment()
method within my TransactionService
class relies on the Account
class to check if UPI payments are enabled for a given account number.
To avoid invoking the real isUpiAllowed()
method during testing, I intend to mock the Account constructor.
This will allow me to inject a mock Account object that provides a controlled response when its isUpiAllowed()
method is called.
This mocking strategy is generally applicable and can be used with other dependencies, such as RestTemplate
for mocking API responses.
public class TransactionService
{
public boolean upiPayment(Long accountNumber, BigDecimal amount) {
Account account = new Account(); // we'll mock this constructor
boolean upiAllowed = account.isUpiAllowed(accountNumber, amount);
if (upiAllowed) {
System.out.println("transaction completed");
return true;
}
return false;
}
}
public class Account {
public boolean isUpiAllowed(Long accountNumber, BigDecimal amount) {
System.out.println("Checking is UPI transaction active for account " + accountNumber + " for amount " + amount);
return Objects.nonNull(accountNumber) && accountNumber > 1
Objects.nonNull(amount) && amount.compareTo(BigDecimal.valueOf(5000d)) < 0;
}
}
Mocking the Account Constructor for JUnit Tests
@Test
void upiTransaction() {
try (MockedConstruction<Account> accountMockedConstruction = Mockito.mockConstruction(Account.class, (mock, context) ->
Mockito.when(mock.isUpiAllowed(ArgumentMatchers.anyLong(), ArgumentMatchers.any()))
.thenReturn(true))) {
boolean transactionStatus = transactionService.upiPayment(1234567890L, BigDecimal.TEN);
assertTrue(transactionStatus);
}
}
Mockito.mockConstruction() method: Explanation
Mockito's mockConstruction()
method provides a powerful way to mock the instantiation of new objects, offering greater flexibility than older approaches like whenNew()
.
It's particularly useful when dealing with classes you don't directly control, or when you need to mock the creation of objects within the system under test.
This approach allows you to intercept and control the behavior of newly created instances, enabling you to isolate dependencies, simulate specific scenarios, and thoroughly test your code
The following overloaded version of the mockConstructor
method is used in this example.
public static <T> org.mockito.MockedConstruction<T> mockConstruction(java.lang.Class<T> classToMock, org.mockito.MockedConstruction.MockInitializer<T> mockInitializer) { /* compiled code */ }
MockInitializer interface: Explanation
MockInitializer
in Mockito is a powerful mechanism that allows you to customize and extend the initialization process of your mocks.
It provides a way to execute specific setup logic before mocks are fully initialized, giving you fine-grained control over their behavior and state.
This is particularly useful for handling complex initialization scenarios, setting up default values, or integrating with other testing frameworks.
To customize our mock, we simply implement the following prepare()
method.
@java.lang.FunctionalInterface
static interface MockInitializer <T> {
void prepare(T t, org.mockito.MockedConstruction.Context context) throws java.lang.Throwable;
}
static interface Context {
int getCount();
java.lang.reflect.Constructor<?> constructor();
java.util.List<?> arguments();
}
Conclussion
In this tutorial, we've explored the powerful capabilities of Mockito for mocking constructors, a crucial technique for effective unit testing, especially when dealing with complex dependencies or legacy code.
We've seen how mockConstruction()
provides a flexible and modern approach to intercept and control object creation, enabling us to isolate the system under test and simulate various scenarios.
The complete code for this project is available on my GitHub repository (getButton) #text=(GitHub) #icon=(share) #color=(#000000)
Keep learning and keep growing.