I have a class that has the @Slf4j annotation.
I try to write a test and mock the Logger, but it does not work.
@RequiredArgsConstructor
@Slf4j
public abstract class ExampleClass {
protected final PropsClass properties;
protected void logInfo(..) {
log.info(...);
clearMappedDiagnosticContext();
}
}
This is how the test looks like:
@RunWith(MockitoJUnitRunner.class)
public class ExampleClassTest {
@Mock
Logger logger;
@Mock
PropsClass properties;
@InjectMocks
ExampleClass exampleClass;
@Test
public void logSomethingtest() {
...
exampleClass.logInfo(...);
Mockito.verify(logger).info(marker, "foo bar {}", ...);
}
This is the error I get:
Wanted but not invoked:
logger.info(
MY_MARKER,
"..........",
"....",
"....",
0L
);
Actually, there were zero interactions with this mock.
The question is, how to mock the Logger?
The lombok @Slf4j
annotation injects code into your class at compile time. Specifically, it will add the following code to your class:
private static final org.slf4j.Logger log =
org.slf4j.LoggerFactory.getLogger(LogExample.class);
@InjectMocks
is telling Mockito to create an instance of your class and inject mocks as its dependencies at runtime.
The logger is injected at compile time. Dependecies are injected at runtime. That's why your logger is not mocked and cannot be mocked like this. If you look at the injected logger code above, you will understand, that the only way to mock the logger is to mock the LoggerFactory (Mockito can mock static methods since version 3.4, IIRC) and make it return the logger mock.
NB: Making mocks return mocks is usually a bad idea and should be avoided. @Slf4j
is too convenient to not be used. It's a tradeoff.
NB: If all you want it silencing the logger, then you could also just configure it to shut up in your tests.
As Mockito is able to mock also static methods since version 3.4.0 is able to mock static methods too, you can simply stub the access to to logger like this:
@Test
void logmessageInCaseOfPositiveValidationIsWritten() {
Logger mockedLogger = Mockito.mock(Logger.class);
try (MockedStatic<LoggerFactory> context = Mockito.mockStatic(LoggerFactory.class)) {
context.when(() -> LoggerFactory.getLogger(Mockito.any(Class.class)))
.thenReturn(mockedLogger);
// Your test code and your assertions
Mockito.verify(mockedLogger)
.debug("I am the expected message with param {}",
"paramvalue");
}
}
Do not forget to create the needed file test/resources/mockito-extensions/org.mockito.plugins.MockMaker
with the context below to enable static mocking:
mock-maker-inline
Written for version 4.5.1 of Mockito.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With