繁体   English   中英

如何使用JMockIt对Log4j进行单元测试?

[英]How can I unit test Log4j using JMockIt?

使用静态方法在类中声明Logger(或任何静态字段)时:

public class Foo {
  private static final Logger LOGGER = Logger.getLogger(Foo.getClass);
}

我可以断言调用它的方法(用于审计)的正确方法是什么?

以下方法可行 ,但setField似乎是错误的方法,无法使用@Tested批注来允许自动注入。

@Mocked Logger logger
new Expectations() {
  {
    setField(unitUnderTest, logger);
  }
}

JMockIt似乎提供了@UsingMocksAndStubs(Log4jMocks.class)的解决方案,但是这不允许Expectations,因为它导致调用getLogger()返回一个真实但无用的Logger而不是一个模拟的实例。

这很简单:

@Test
public void verifyAuditing(@Cascading final Logger logging)
{
    // Call code under test which will create auditing records.

    new Verifications() {{ logging.info("expected audit info"); }};
}

使用@Cascading会导致Logger在“级联”模式下被@Cascading ,其中每个返回引用类型的方法都会自动创建一个模拟实例。 初始模拟实例logging代表所有此类实例。

这个问题和答案描述了我希望如此完美地完成的工作,但是我在尝试实现这里接受的答案时没有找到任何乐趣 - 努力使其工作但是我的配置可能在某些重要方面有所不同? 所以,如果它能帮助其他任何人,我会提供这个公认的疯狂的替代方案,它确实具有实际工作的优势(Java6,JMockit 1.7,JUnit 4.8.1,SLF4J 1.5.10)。

一般策略是实现一个slf4j Logger,它将委托给一个模拟记录器。 这种组合似乎让我能够以对被测系统完全无创的方式将所有内容连接起来。 在被测系统中,我有:

private static Logger log = org.slf4j.LoggerFactory.getLogger(SUT.class);

而且,当然,日志的各种用法..

在我的测试班..

private static final TestLogger log = new TestLogger();

@Mocked
private Logger mockLogger;

@Tested
SUT sut = new SUT();

@BeforeClass
public static void replaceLogger() {
    new MockUp<LoggerFactory>() {
        @SuppressWarnings("rawtypes")
        @Mock
        Logger getLogger(Class clazz) {
            return log;
        }
    };
}

@Before
public void setup() {
    // go ahead and prefix this with name of test class, since log is static..
    log.setLogger(mockLogger);
}

@Test
public void ensure_some_behavior_happens() {
    new NonStrictExpectations() {{
        ...
    }};

    sut.someMethodOfInterest();

    new Verifications() {{
        mockLogger.warn("expected logging"); maxTimes = 1;
    }};
}

好吧现在疯狂的部分 - 日食帮助了很多,但仍然是实施Logger的一个主要痛苦。 真的让我欣赏界面隔离原则。

public class TestLogger implements Logger {
    Logger l = null;
    public void setLogger(Logger log) { l = log; }
    public String getName() { return l != null ? l.getName() : ""; }
    public boolean isTraceEnabled() { return l != null ? l.isTraceEnabled() : false; }
    public void trace(String msg) { if (l != null) l.trace(msg); }
    public void trace(String format, Object arg) { if (l != null) l.trace(format, arg); }
    public void trace(String format, Object arg1, Object arg2) { if (l != null) l.trace(format, arg1, arg2); }
    public void trace(String format, Object[] argArray) { if (l != null) l.trace(format, argArray); }
    public void trace(String msg, Throwable t) { if (l != null) l.trace(msg, t); }
    public boolean isTraceEnabled(Marker marker) { return l != null ? l.isTraceEnabled(marker) : false; }
    public void trace(Marker marker, String msg) { if (l != null) l.trace(marker, msg); }
    public void trace(Marker marker, String format, Object arg) { if (l != null) l.trace(marker, format, arg); }
    public void trace(Marker marker, String format, Object arg1, Object arg2) { if (l != null) l.trace(marker, format, arg1, arg2); }
    public void trace(Marker marker, String format, Object[] argArray) { if (l != null) l.trace(marker, format, argArray); }
    public void trace(Marker marker, String msg, Throwable t) { if (l != null) l.trace(marker, msg, t); }
    public boolean isDebugEnabled() { return l != null ? l.isDebugEnabled() : false; }
    public void debug(String msg) { if (l != null) l.debug(msg); }
    public void debug(String format, Object arg) { if (l != null) l.debug(format, arg); }
    public void debug(String format, Object arg1, Object arg2) { if (l != null) l.debug(format, arg1, arg2); }
    public void debug(String format, Object[] argArray) { if (l != null) l.debug(format, argArray); }
    public void debug(String msg, Throwable t) { if (l != null) l.debug(msg, t); }
    public boolean isDebugEnabled(Marker marker) { return l != null ? l.isDebugEnabled(marker) : false; }
    public void debug(Marker marker, String msg) { if (l != null) l.debug(marker, msg); }
    public void debug(Marker marker, String format, Object arg) { if (l != null) l.debug(marker, format, arg); }
    public void debug(Marker marker, String format, Object arg1, Object arg2) { if (l != null) l.debug(marker, format, arg1, arg2); }
    public void debug(Marker marker, String format, Object[] argArray) { if (l != null) l.debug(marker, format, argArray); }
    public void debug(Marker marker, String msg, Throwable t) { if (l != null) l.debug(marker, msg, t); }
    public boolean isInfoEnabled() { return l != null ? l.isInfoEnabled() : false; }
    public void info(String msg) { if (l != null) l.info(msg); }
    public void info(String format, Object arg) { if (l != null) l.info(format, arg); }
    public void info(String format, Object arg1, Object arg2) { if (l != null) l.info(format, arg1, arg2); }
    public void info(String format, Object[] argArray) { if (l != null) l.info(format, argArray); }
    public void info(String msg, Throwable t) { if (l != null) l.info(msg, t); }
    public boolean isInfoEnabled(Marker marker) { return l != null ? l.isInfoEnabled(marker) : false; }
    public void info(Marker marker, String msg) { if (l != null) l.info(marker, msg); }
    public void info(Marker marker, String format, Object arg) { if (l != null) l.info(marker, format, arg); }
    public void info(Marker marker, String format, Object arg1, Object arg2) { if (l != null) l.info(marker, format, arg1, arg2); }
    public void info(Marker marker, String format, Object[] argArray) { if (l != null) l.info(marker, format, argArray); }
    public void info(Marker marker, String msg, Throwable t) { if (l != null) l.info(marker, msg, t); }
    public boolean isWarnEnabled() { return l != null ? l.isWarnEnabled() : false; }
    public void warn(String msg) { if (l != null) l.warn(msg); }
    public void warn(String format, Object arg) { if (l != null) l.warn(format, arg); }
    public void warn(String format, Object[] argArray) { if (l != null) l.warn(format, argArray); }
    public void warn(String format, Object arg1, Object arg2) { if (l != null) l.warn(format, arg1, arg2); }
    public void warn(String msg, Throwable t) { if (l != null) l.warn(msg, t); }
    public boolean isWarnEnabled(Marker marker) { return l != null ? l.isWarnEnabled(marker) : false; }
    public void warn(Marker marker, String msg) { if (l != null) l.warn(marker, msg); }
    public void warn(Marker marker, String format, Object arg) { if (l != null) l.warn(marker, format, arg); }
    public void warn(Marker marker, String format, Object arg1, Object arg2) { if (l != null) l.warn(marker, format, arg1, arg2); }
    public void warn(Marker marker, String format, Object[] argArray) { if (l != null) l.warn(marker, format, argArray); }
    public void warn(Marker marker, String msg, Throwable t) { if (l != null) l.warn(marker, msg, t); }
    public boolean isErrorEnabled() { return l != null ? l.isErrorEnabled() : false; }
    public void error(String msg) { if (l != null) l.error(msg); }
    public void error(String format, Object arg) { if (l != null) l.error(format, arg); }
    public void error(String format, Object arg1, Object arg2) { if (l != null) l.error(format, arg1, arg2); }
    public void error(String format, Object[] argArray) { if (l != null) l.error(format, argArray); }
    public void error(String msg, Throwable t) { if (l != null) l.error(msg, t); }
    public boolean isErrorEnabled(Marker marker) { return l != null ? l.isErrorEnabled(marker) : false; }
    public void error(Marker marker, String msg) { if (l != null) l.error(marker, msg); }
    public void error(Marker marker, String format, Object arg) { if (l != null) l.error(marker, format, arg); }
    public void error(Marker marker, String format, Object arg1, Object arg2) { if (l != null) l.error(marker, format, arg1, arg2); }
    public void error(Marker marker, String format, Object[] argArray) { if (l != null) l.error(marker, format, argArray); }
    public void error(Marker marker, String msg, Throwable t) { if (l != null) l.error(marker, msg, t); }
}

无论如何,我肯定会看到其他解决方案中的其中一个是否有效,但如果你应该绝望,也许可以尝试这种方法。

编辑:好的......在我将TestLogger转变为动态代理实现之后,我对这种方法感觉更好。 这是怎么做的..

首先,给自己一个界面..

public interface TestLogger extends Logger {
    void setLogger(org.slf4j.Logger wrapped);
}

然后你需要一个调用处理程序..

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.slf4j.Logger;

public class TestLoggerInvocationHandler implements InvocationHandler {
    private Logger wrapped;

    private TestLoggerInvocationHandler() {
        super();
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("setLogger".equals(method.getName())) {
            wrapped = (Logger)args[0];
            return null;
        }
        return wrapped != null ? method.invoke(wrapped, args) : null;
    }

    public static TestLogger createTestLogger() {
        return (TestLogger) (Proxy.newProxyInstance(TestLogger.class.getClassLoader(),
                new Class[] { TestLogger.class }, new TestLoggerInvocationHandler()));
    }

}

只需在测试类中调用静态工厂方法,你应该好好去 - 毕竟不是那么疯狂!

您可以将字段声明为非静态字段,默认情况下使用Logger.getLogger(...),然后提供一个setter来注入模拟的记录器。 如果您在与原始类相同的包中使用Test,则至少可以声明setter包受保护。

据我所知,getLogger将始终返回相同的日志记录实例,因此即使您有数百个类的实例,也没有数百个Logger。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM