Mock Java Constructors and Their Object Creation With Mockito
source link: https://rieckpil.de/mock-java-constructors-and-their-object-creation-with-mockito/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Starting with version 3.5.0, Mockito can now mock constructors and return a mock on every object construction. Like mocking static method calls, we can define the scope of returning a mock when constructing an object. While the practical use cases for this feature might be limited, at least that's the next step towards replacing PowerMock with Mockito. Let's take a look at this feature in action.
Configuration Of The InlineMockMaker
This new feature of Mockito is only available if we use an InlineMockMaker
. This interface extends the MockMaker
interface that define Mockito's internal API to create mocks. There are multiple implementations for this interface, and the default one is the SubclassByteBuddyMockMaker
.
To override this default MockMaker
and use a InlineMockMaker
instead, we can replace our mockito-core
dependency with mockito-inline
:
If for some reasons we are not able to add this dependency to our project and only rely on mockito-core
, we can still configure the InMockMaker
with an extension file.
Therefore, put a org.mockito.plugins.MockMaker
file inside src/test/resources/mockito-extensions
with the following content:
For those who are using the Spring Boot Starter Test to manage the versions of the basic testing libraries, refer to the Mockito setup section of this article.
Mock A Java Constructor With Mockito
Let's see how we can mock the construction of an object with Mockito. As an example, we'll use the following Java class:
Furthermore, let's assume an instance of this PaymentProcess
is created manually inside the CheckoutService
using the new
operator.
If we would use constructor/field/setter injection instead, this Mockito feature wouldn't be relevant. In such cases, we can pass the mocked version of a collaborator and don't have to mock the constructor.
When writing a unit test for the purchaseProduct
method, we want to mock collaborators of our class under test. For this purpose, we can now use the new feature of Mockito and mock the object construction of the PaymentProcessor
inside purchaseProduct
.
The new method that makes mocking object constructions possible is Mockito.mockConstruction()
. As a first argument, this method takes a non-abstract Java class that constructions we're about to mock. In the example above, we use an overloaded version of mockConstruction()
to pass a MockInitializer
as a second argument. This MockInitializer
is a callback that we use to stub the behavior of the mock.
We can define the scope of mocking any object creation for our PaymentProcessor
by using Java's try-with-resources construct, as the MockedConstruction
is extending the AutoClosable
interface. This allows mocking the object construction only for a temporary and user-defined purpose.
If you've already mocked a static method with Mockito, this setup might seem familiar.
Let's take a look at further examples of how we can use this new feature of Mockito.
Further Examples To Mock Constructors
First, let's come back to the scope of mocking the object construction. Whenever we use the try-with-resources
(which is highly recommended for this use case) construct, every constructor call inside this block is mocked. Any object creation before or after returns a real instance:
Furthermore, as all object constructions for this class are mocked, it doesn't matter which public constructor we use:
In the test above, all object creations are mocked, independent of which constructor of PaymentProcessor
we use. We can even inspect how many mock objects were created during a test using the mock controller that is returned from mockConstruction()
.
As the last example, let's take a look at mockConstructionWithAnswer
. Using this method, we can add a default Answer
and additional Answer
s that define our mock's behavior.
In our example, we can always return a BigDecimal
as our PaymentProcessor
only has one public method. For classes with multiple methods and different return types, either use the passed invocation
to determine what to return or use the mockConstruction()
that takes a MockInitializer
for type-safe stubbings.
Summary
As we can now mock our constructors and static method calls with Mockito, the need for PowerMock becomes less important. With this feature, you can get rid of PowerMock if you've only used it for those two purposes and rely solely on Mockito.
However, we shouldn't jump into using this feature from now on for every test. Mocking the object construction, e.g. of internally used value objects, is an anti-pattern which we should avoid.
Having all collaborators of a class injected by its public constructor, this feature's possible use cases are limited.
Are you looking for further practical resources on Mockito? Consider enrolling in my Hands-On With Mockito Online Course to learn the ins and outs of the most popular mocking library for JVM applications.
You can find the source code for this blog post on GitHub.
Have fun mocking your constructors,
Philip
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK