I want to check the log of the log output at the time of testing when using an external logging API such as SLF4J.
Mock the log so that you can control the output of the log with test code
For those who want to take a quick look at the code, "[Sample Code](https://qiita.com/yusha3/items/c9576bbe8b6cc5b27897#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%" You can find it in the chapter "AB% E3% 82% B3% E3% 83% BC% E3% 83% 89)".
Procedure flow
@Captor
private ArgumentCaptor<LoggingEvent> captorLoggingEvent;
ArgmentCaptor is used when you want to verify that a stubbed method in a mockito class has been called properly, or that the appropriate arguments have been passed to that method. This time, we will capture the argument of LoggingEvent which is the type of log output.
@Mock
private Appender mockAppender;
final Logger logger = (Logger) LoggerFactory.getLogger([Class name to be tested].class);
logger.addAppender(mockAppender);
Define your own logger variable without using @ Slf4j and add a mocked Appender to logger.
Appender is the interface used to set the log output destination.
Appender can be set to Logger with the addAppender ()
method.
Here, you can mock the log output destination of logger by preparing a mock Appender and ʻaddAppender ()` it.
verify(mockAppender).doAppend(captorLoggingEvent.capture());
assertEquals("INFO", captorLoggingEvent.getValue().getLevel().toString());
doAppend
has an event object as an argument.
The role that the append Appender logs
Only the last log can be caught by the above method. Assign to a list to catch all logs.
//Extract only application logs
List<LoggingEvent> events = captorLoggingEvent.getAllValues().stream()
.collect(Collectors.toList());
package com.zozo.tech.search.personalize.api.logic;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class Sample {
public void doLogging() {
log.info("sample");
log.info("sample access_log.");
log.info("sample access_log 2.");
}
}
package com.zozo.tech.search.personalize.api.logic;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.Appender;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@SpringBootTest
public class SampleTest {
@Captor
private ArgumentCaptor<LoggingEvent> captorLoggingEvent;
@Mock
private Appender mockAppender;
@InjectMocks
@Autowired
Sample sample;
@BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
void test() throws Exception {
Logger logger = (Logger) LoggerFactory.getLogger(Sample.class);
logger.addAppender(mockAppender);
sample.doLogging();
verify(mockAppender).doAppend(captorLoggingEvent.capture());
//Check if INFO level log is output
assertEquals("INFO", captorLoggingEvent.getValue().getLevel().toString());
//Extract only application logs
List<LoggingEvent> events = captorLoggingEvent.getAllValues().stream()
.filter(e -> e.getMessage().contains("access_log"))
.collect(Collectors.toList());
assertEquals(2, events.size());
}
}
Recommended Posts