У меня есть приложение весенней загрузки 2, работающее на Java 10 с использованием SLF4J и входом в систему в качестве основного регистратора.
Учитывая следующий компонент пружины:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@Service
public class MyClass {
private static final Logger LOG = LoggerFactory.getLogger(MyClass.class);
public void hello() {
// more logic...
LOG.trace("World");
}
}
И тест, который желает проверить вывод журнала (представьте себе более сложный сценарий, в котором журнал будет содержать переменные и контекстную информацию) или факт создания сообщения журнала, считается критическим.
import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.test.rule.OutputCapture;
import static org.hamcrest.Matchers.containsString;
public class MyClassTest {
private final MyClass myClass = new MyClass();
@Rule
public final OutputCapture outputCapture = new OutputCapture();
@Test
public void successShouldLogSuccessMessages() {
myClass.hello();
outputCapture.expect(containsString("World"));
}
}
Для того, чтобы этот тест прошел, уровень лога должен быть установлен на TRACE
. Я заметил непредсказуемое поведение, при котором тест либо проваливался, либо проходил в зависимости от порядка выполнения тестов - см. Кажущийся случайным сбой теста с Maven и Spring Boot 2, когда вводится WebFluxTest
Я исследовал несколько вариантов, ни один из которых не кажется «идеальным», но работает.
- Укажите файл конфигурации обратного входа в путь к тестовому классу, который задает уровень журнала для трассировки, по крайней мере, для этого одного класса.
- Установите уровень журнала этого класса равным
TRACE
в классе свойств приложения пружины и запустите тест в контексте пружины.
- Создайте настройку и разверните ее в классе теста, который программно изменяет уровень журнала во время выполнения теста, а затем сбрасывает его после.
Решение, которое у меня есть в настоящее время, состоит в том, чтобы позволить Spring выполнить настройку регистратора и сделать тест контекстным тестом Spring (и убедиться, что он работает быстро, загружая только один компонент, который мне нужен) следующим образом:
@RunWith(SpringRunner.class)
@SpringBootTest(properties = "spring.profiles.active=test")
@ContextConfiguration(classes = MyClass.class)
public class MyClassTest {
private final MyClass myClass = new MyClass();
@Rule
public final OutputCapture outputCapture = new OutputCapture();
@Test
public void successShouldLogSuccessMessages() {
myClass.hello();
outputCapture.expect(containsString("World"));
}
}
Где содержание application-test.properties
:
logging.level.com.example.MyClass=TRACE
Это решение работает, не требуется, чтобы я программно поигрался с регистраторами или поместил конфигурацию обратного входа в classpath, что делает все совершенно независимым от базовой структуры журналов, а сохранение конфигурации обратного входа в стороне от пути classpath теста также означает другие тесты, которые не волнует логирование не подбирает конфиг.
Тем не менее, это кажется "странным", я никогда не видел, чтобы кто-то использовал весенние тесты таким образом (для тестирования одного компонента без зависимостей и прямой зависимости от контекста). Тест начал свою жизнь как плановый тест POJO без заботы о весне, и он кажется более «чистым», чем и остается таким.
Есть ли передовая практика, применяемая при попытке проверить выходные данные объекта через SLF4J?