Keywords: Java | Unit Testing | Mockito | JUnit
Abstract: This article explores a common pitfall in Mockito unit testing where mocking the class under test leads to 'Wanted but not invoked' errors. Through a detailed example, it analyzes the cause of interaction缺失 and provides step-by-step solutions for correct test strategies, emphasizing the importance of testing real logic for code quality assurance.
Introduction
In Java development, unit testing is crucial for ensuring code reliability, with Mockito widely used to mock external dependencies for isolation. However, improper use of mocks can lead to test failures, such as the error message "Wanted but not invoked: Actually, there were zero interactions with this mock". Based on a real case, this article analyzes the cause of this error and provides solutions.
Problem Case
Consider a unit test scenario aimed at verifying whether a method calls the addTemplate method of PdfContentByte. The developer wrote the following test code:
public void computeEyeletsNoMirror() {
PdfWriter pdfWriter = Mockito.mock(PdfWriter.class);
PdfContentByte pdfContentByte = Mockito.mock(PdfContentByte.class);
Mockito.when(pdfWriter.getDirectContent()).thenReturn(pdfContentByte);
WithDefinitions withDefinitions = Mockito.mock(WithDefinitions.class); // Error: mocking the class under test
float lineLeft = BORDER_LEFT + EYELET_MARGIN;
float lineBottom = BORDER_BOTTOM + EYELET_MARGIN;
withDefinitions.setEyeletDistMinH(20);
withDefinitions.setEyeletDistMinV(20);
withDefinitions.setMirror(false);
withDefinitions.computeEyelets(pdfWriter);
Mockito.verify(pdfContentByte).addTemplate(
Mockito.any(PdfImportedPage.class),
Mockito.eq(lineLeft),
Mockito.eq(lineBottom)
);
}During test execution, an exception is thrown indicating that the addTemplate method was not called, because the WithDefinitions object is mocked, and its methods computeEyelets and setEyelet are replaced with default mock implementations that do nothing.
Cause Analysis
Mockito's mock mechanism creates a proxy object that intercepts all method calls and returns预设 values or empty behavior. When mocking the class under test (e.g., WithDefinitions), real methods do not execute, causing dependent method calls (e.g., addTemplate) never to occur. This violates the core principle of unit testing: verifying real code behavior.
Solution
According to best practices, use real objects to test their logic and only mock external dependencies. Correct the test code by replacing the mock with a real WithDefinitions instance:
public void computeEyeletsNoMirror() {
PdfWriter pdfWriter = Mockito.mock(PdfWriter.class);
PdfContentByte pdfContentByte = Mockito.mock(PdfContentByte.class);
Mockito.when(pdfWriter.getDirectContent()).thenReturn(pdfContentByte);
WithDefinitions withDefinitions = new WithDefinitions(); // Use real instance
float lineLeft = BORDER_LEFT + EYELET_MARGIN;
float lineBottom = BORDER_BOTTOM + EYELET_MARGIN;
withDefinitions.setEyeletDistMinH(20);
withDefinitions.setEyeletDistMinV(20);
withDefinitions.setMirror(false);
withDefinitions.computeEyelets(pdfWriter);
Mockito.verify(pdfContentByte).addTemplate(
Mockito.any(PdfImportedPage.class),
Mockito.eq(lineLeft),
Mockito.eq(lineBottom)
);
}This way, the computeEyelets method executes真的, calling setEyelet and triggering addTemplate, allowing the verification to pass. Meanwhile, PdfWriter and PdfContentByte are mocked to isolate PDF-related dependencies, ensuring the test focuses on business logic.
Additional Notes
In complex scenarios, if partial mocking is needed, Mockito's spy functionality can be used, but it is generally recommended to avoid mocking the class under test. Additionally, ensure mock objects are set up correctly to simulate dependency behaviors, such as using Mockito.when to define return values.
Conclusion
The goal of unit testing is to verify code logic correctness. Mockito should be applied to mock external dependencies, not the class under test itself. By adhering to this principle, you can avoid "Wanted but not invoked" errors, improve test coverage and reliability, and thus support high-quality software development.