我想知道使用powermock(和mockito)模拟org.apache.log4j最简单,最简洁的方法是什么。
我尝试了一些方法(我不会在这里说明),但还没有找到实现我想要的方法。我在下面创建了一个简单的类来测试,我想调用run方法并验证是否已经调用了log.info消息。我该怎么做呢?当你知道怎么做时,我相信这很容易!
(我正在使用@Rule,因为我想在弹簧测试下运行,但这应该没有区别。)
感谢millon提供正确的代码。
import org.apache.log4j.Logger;
import org.junit.Rule;
import org.junit.Test;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.rule.PowerMockRule;
public class MockLog4JTest
{
@Rule
public PowerMockRule rule = new PowerMockRule();
private static class ClassUnderTest
{
private static Logger logger = Logger.getLogger(ClassUnderTest.class);
public void run() {
logger.info("Hello.");
}
}
@Test
public void testLog()
{
ClassUnderTest classUnderTest = new ClassUnderTest();
classUnderTest.run();
}
}
答案 0 :(得分:10)
Chris和Fildor尝试模拟Logger.getLogger()是正确的。不幸的是,Log4J的工作方式在技术上很棘手。
以下是我根据您的上述示例提出的(测试过的)代码。
import org.apache.log4j.Logger;
public class ClassUnderTest {
private static Logger logger = Logger.getLogger(ClassUnderTest.class);
public void run() {
logger.info("Hello.");
}
}
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.powermock.api.mockito.PowerMockito.mock;
import org.apache.log4j.Logger;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.powermock.reflect.Whitebox;
@PrepareForTest(ClassUnderTest.class)
public class MockLog4JTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
@BeforeClass
public static void oneTimeSetup() {
System.setProperty("log4j.defaultInitOverride", Boolean.toString(true));
System.setProperty("log4j.ignoreTCL", Boolean.toString(true));
}
@Test
public void testLog()
{
ClassUnderTest classUnderTest = new ClassUnderTest();
Logger mockLogger = mock(Logger.class);
Whitebox.setInternalState(ClassUnderTest.class, "logger", mockLogger);
classUnderTest.run();
verify(mockLogger).info(eq("Hello."));
}
}
我选择使用Whitebox将被测试类上的静态字段直接设置为mockLogger
实例。在那之后,验证非常简单。
答案 1 :(得分:1)
Matt Lachman的回答非常适合我 - 直到我尝试使用Spring。 在Spring中,我在尝试将记录器更改为时遇到了运行时异常 mockLogger。为了让它在Spring中运行,我必须执行以下操作:
更改行
Whitebox.setInternalState(ClassUnderTest.class, "logger", mockLogger);
到
EncapsulationBreaker.setFinalStatic(ClassUnderTest.class.getDeclaredField("logger"), mockLogger);
并且EncapsulationBreaker看起来像这样:
public class EncapsulationBreaker
{
public static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
}
要阅读有关设置私有静态最终成员的更多信息,请参阅 Change private static final field using Java reflection
另请注意,我只是出于测试目的而这样做。