Как установить уровень журнала DEBUG во время тестов Junit?
Я использую SLF4J с LOG4J, и конфигурации обычно находятся в log4j.properties
, и это устанавливает уровень журнала на INFO.
Однако во время тестов я хотел бы установить журналы на DEBUG.
Я не вижу способа автоматизировать это, ни иметь что-то вроде log4j.tests.properties
это будет загружено только во время испытаний.
Итак, я попытался сделать это программно в настройках теста (@BeforeClass):
LogManager.getRootLogger().setLevel(Level.ALL);
Без успеха...
Я использую эти версии:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
Как мне достичь этого результата?
РЕДАКТИРОВАТЬ: Я думаю, что я не был достаточно ясен. Этот вопрос не о настройке правильного уровня журнала... Речь идет об установке уровня журнала DEBUG при запуске тестов Junit и настройке уровня журнала INFO в любой другой ситуации. Я хочу автоматизировать это.
6 ответов
Вам не нужно предоставлять JVM другую реализацию журнала.
Лог-код ищет log4j.properties
файл с использованием пути к классам. Так что все, что вам нужно сделать, это убедиться, что ваш тест log4j.properties
Файл находится в месте, которое он найдет до выпуска файла.
Я использую Maven, который выкладывает файлы в каталоги, чтобы сделать это проще. Мой релиз log4j.properties
идет в каталог src/main/resources
, Моя тестовая версия идет в src/test/resources
, Путь сборки Eclipse (classpath) настроен для поиска src/test/resources
до src/main/resources
, так что ваши юнит-тесты используют тестовый файл. Инструкции по сборке JAR (или WAR) используют файлы из src/main/resources
,
Изменение уровня журнала ниже ROOT будет работать для junit, чтобы установить желаемый уровень ведения журнала.
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
@Before
public void setUp() {
final Logger logger = (Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
logger.setLevel(Level.ALL);
}
Вы можете использовать org.apache.logging.log4j.core.config.Configurator
который имеет setAllLevels
метод.
В своем тесте вы можете использовать его в @Before
метод:
@Before
public void changeLogLevel() {
Configurator.setAllLevels("", Level.ALL);
}
ПРИМЕЧАНИЕ: протестировано с привязкой org.slf4j:slf4j-log4j12:1.7.26
Возможно , это не совсем связано с вопросом в первую очередь, однако запрос Google приведет большинство разработчиков к этой теме, когда они будут искать способ
как изменить уровень журнала для некоторых методов тестирования junit.
Можно использовать настраиваемое Junit MethodRule, которое обращается к средствам ведения журнала и повторно настраивает уровень журнала для каждого пакета.
С помощью классов ниже вы можете добиться этого. Он устанавливает уровень журнала для пакетов и классов, как это определено в аннотации метода тестирования, и по завершении теста возвращает регистраторы в их исходное состояние. Мы предполагаем, что в настоящее время уровень журнала по умолчанию установлен на INFO.
@Test
@LogLevel(packageToLevel = { "my.java.package=DEBUG", "my.other.java.package.ClassNeedsTracing=TRACE" })
public void allLogsOfThatPackageAreInDebugNow() {
...
}
@Test
@LogLevel(packageToLevel = { "my.java.package=TRACE", "my.java.package.ClassNoTracing=TRACE" })
public void allLogsOfThatPackageAreInTraceNowExceptOneClass() {
...
}
Для этого вам нужно указать правило тестирования в своем тестовом классе:
@Rule
LogLevelRule logLevelRule = new LogLevelRule();
Необходимые классы указаны ниже:
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
/**
* a Junit Rule that check for LogLevel annotation on methods and activates the configured log level per package. After
* the test was executed, restores the previous log level.
*/
public class LogLevelRule implements MethodRule {
@Override
public Statement apply(Statement base, FrameworkMethod method, Object target) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
// activate log level desired, remember what they were
Map<String, Level> existingPackageLogLevel = new HashMap<>();
LogLevel logLevelAnnotation = method.getAnnotation(LogLevel.class);
if (logLevelAnnotation != null) {
activate(logLevelAnnotation.packageToLevel(), existingPackageLogLevel);
}
// run the test
Throwable testFailure = evaluateSafely(base);
// revert the log level back to what it was
if (!existingPackageLogLevel.isEmpty()) {
deactivate(existingPackageLogLevel);
}
if (testFailure != null) {
throw testFailure;
}
}
/**
* execute the test safely so that if it fails, we can still revert the log level
*/
private Throwable evaluateSafely(Statement base) {
try {
base.evaluate();
return null;
} catch (Throwable throwable) {
return throwable;
}
}
};
}
/**
* activates the log level per package and remember the current setup
*
* @param packageToLevel
* the configuration of the annotation
* @param existingPackageLogLevel
* where to store the current information
*/
protected void activate(String[] packageToLevel, Map<String, Level> existingPackageLogLevel) {
for (String pkgToLevel : packageToLevel) {
String[] split = pkgToLevel.split("=");
String pkg = split[0];
String levelString = split[1];
Logger logger = LogManager.getLogger(pkg);
Level level = logger.getLevel();
existingPackageLogLevel.put(pkg, level);
logger.setLevel(Level.toLevel(levelString));
}
}
/**
* resets the log level of the changes packages back to what it was before
*
* @param existingPackageLogLevel
*/
protected void deactivate(Map<String, Level> existingPackageLogLevel) {
for (Map.Entry<String, Level> e : existingPackageLogLevel.entrySet()) {
LogManager.getLogger(e.getKey()).setLevel(e.getValue());
}
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* marks a method to use a different log level for the execution phase
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface LogLevel {
String[] packageToLevel();
}
Обычно LEVEL.FINEST должен это делать... но взгляните на http://saltnlight5.blogspot.mx/2013/08/how-to-configure-slf4j-with-different.html чтобы увидеть рассмотрение реализаций каркасов ведения журналов.
Как уже упоминалось, система logback использует
src/test/resources/logback-test.xml
файл для настройки уровней журнала модульного тестирования. Вот пример файла:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
<appender name="ConsoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
<logger name="com.example.report" level="TRACE" additivity="false">
<appender-ref ref="ConsoleAppender" />
</logger>
</Configuration>
В этом примере корневой (по умолчанию) уровень журнала установлен на
DEBUG
. Классы в
com.example.report
пакет регистрирует свои сообщения в
TRACE
уровня и ниже.