Ответ 1
Лучший способ сделать это - создать пользовательский Listener. Будучи инициализированным до сервлета JSF, он должен настроить мост jul-to-slf4j в contextInitialized(ServletContextEvent)
.
Я нашел полезную статью, в которой объясняется, как заставить Джерси использовать SLF4J вместо JUL. Теперь мой unit test выглядит (и он отлично работает):
public class FooTest extends JerseyTest {
@BeforeClass
public static void initLogger() {
java.util.logging.Logger rootLogger =
java.util.logging.LogManager.getLogManager().getLogger("");
java.util.logging.Handler[] handlers = rootLogger.getHandlers();
for (int i = 0; i < handlers.length; i++) {
rootLogger.removeHandler(handlers[i]);
}
org.slf4j.bridge.SLF4JBridgeHandler.install();
}
public FooTest() {
super("com.XXX");
}
@Test
public void testSomething() throws Exception {
// ...
}
}
My pom.xml
включает следующие зависимости:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
Он работает отлично, но я не хочу делать одну и ту же конфигурацию в каждом unit test. Это очевидное дублирование кода, которого я бы хотел избежать. Как я могу сделать это более эффективно?
пс. Может быть, невозможно оптимизировать код выше, и я делаю все, что в моих силах?
Лучший способ сделать это - создать пользовательский Listener. Будучи инициализированным до сервлета JSF, он должен настроить мост jul-to-slf4j в contextInitialized(ServletContextEvent)
.
Если вы используете клиентский API, вы можете вручную перенаправить журналы на slf4j (обратите внимание, что он может сломаться в будущих версиях, хотя это кажется маловероятным):
Logger LOG = LoggerFactory.getLogger(MyClass.class); //slf4j logger
WebTarget ws = ClientBuilder.newClient(config)
.register(new LoggingFilter(new JulFacade(), true));
private static class JulFacade extends java.util.logging.Logger {
JulFacade() { super("Jersey", null); }
@Override public void info(String msg) { LOG.info(msg); }
}
Похоже, что вам нужен дескриптор конфигурации JUL/SLF4J до того, как JUnit начнет тестирование, чтобы его можно было покрыть для всех тестов? Здесь вы можете сделать это.
Выход
MySuite.init()
MySuite()
getSuiteTests()
MyTest.init()
MyTest()
test()
код
@RunWith(AbstractTestSuite.TestSuiteRunner.class)
public abstract class AbstractTestSuite {
public static class TestSuiteRunner extends Suite {
public TestSuiteRunner(Class<?> klass) throws Exception {
super(klass, ((Class<? extends AbstractTestSuite>) klass).newInstance().getSuiteClasses());
}
}
public Class<?>[] getSuiteClasses() {
List<Class<?>> all = new ArrayList<Class<?>>();
for (Class<?> testClass : getSuiteTests()) {
all.add(testClass);
}
return all.toArray(new Class<?>[0]);
}
protected abstract Iterable<Class<?>> getSuiteTests();
}
public class MySuite extends AbstractTestSuite {
public static class MyTest {
static {
System.out.println("MyTest.init()");
}
public MyTest() {
System.out.println("MyTest()");
}
@Test
public void test() {
System.out.println("test()");
assertTrue(true);
}
}
static {
System.out.println("MySuite.init()");
}
public MySuite() {
System.out.println("MySuite()");
}
@Override
protected Iterable<Class<?>> getSuiteTests() {
System.out.println("getSuiteTests()");
return Arrays.asList(new Class<?>[] {MyTest.class});
}
}
В моем приложении "Джерси" (с правильными pom.xml
и logback.xml
) отлично работает только с
SLF4JBridgeHandler.install();
Для тестов вы можете сделать базовый тест abstract с общей конфигурацией и вывести из него другой JUnit:
public abstract class AbstractTest {
private static final Logger LOG = LoggerFactory.getLogger(AbstractTest.class);
static {
SLF4JBridgeHandler.install();
}
@Rule
public ExpectedException thrown = ExpectedException.none();
@Rule
// http://stackoverflow.com/questions/14892125/what-is-the-best-practice-to-determine-the-execution-time-of-the-bussiness-relev
public Stopwatch stopwatch = new Stopwatch() {
@Override
protected void finished(long nanos, Description description) {
...
Это сработало для меня:
public abstract class JerseyTestSFL4J extends JerseyTest {
static {
// Get JerseyTest to use SLF4J instead of JUL
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}
}
а затем мои тесты расширяются JerseyTestSFL4J
.