如何在 JUnit 中模拟静态方法
How to mock static method in JUnit
在带有 slf4j 和 logback 的 spring-boot 环境中的单元测试中,我想确保 LOGGER.isTraceEnabled()
returns 仅对特定测试 class 为真.
原因是,有时我们会用 if (LOGGER.isTraceEnabled()) {...}
保护缓慢且重要的代码。在单元测试中,我们希望确保在打开跟踪时不会破坏应用程序。
被测代码:
public class ClassUnderTest{
private static final Logger LOGGER = LoggerFactory.getLogger(ClassUnderTest.class);
public void doSomething(Calendar gegenwart) {
if (LOGGER.isTraceEnabled()) {
// non trivial code
}
}
}
测试代码:
public class ClassUnderTestUnitTest{
@Test
public void findeSnapshotMitLueke() {
ClassUnderTest toTestInstance = new ClassUnderTest ();
// I want to make sure trace logging is enabled, when
// this method is executed.
// Trace logging should not be enabled outside this
// test class.
toTestInstance.doSomething(Calendar.getInstance());
}
}
您可以使用 PowerMock 轻松创建 LoggerFactory 的静态模拟,并使其 return 成为 Logger 的常规模拟(使用 EasyMock)。然后你只需定义 Logger.isTraceEnabled()
和 Logger.trace()
.
的模拟实现
超出我的想象:
@PrepareForTest({ LoggerFactory.class })
@RunWith(PowerMockRunner.class) // assuming JUnit...
public class ClassUnderTestUnitTest{
@Test
public void findeSnapshotMitLueke() {
Logger mockLogger = EasyMock.createMock(Logger.class);
EasyMock.expect(mockLogger.isTraceEnabled()).andReturn(true);
EasyMock.expect(mockLogger.trace(any()));
EasyMock.expectLastCall().anyTimes() // as trace is a void method.
// Repeat for other log methods ...
PowerMock.mockStatic(LoggerFactory.class);
EasyMock.expect(LoggerFactory.getLogger(ClassUnderTest.class)
.andReturn(mockLogger);
PowerMock.replay(mockLogger, LoggerFactory.class);
ClassUnderTest toTestInstance = new ClassUnderTest ();
// I want to make sure trace logging is enabled, when
// this method is executed.
// Trace logging should not be enabled outside this
// test class.
toTestInstance.doSomething(Calendar.getInstance());
// After the operation if needed you can verify that the mocked methods were called.
PowerMock.verify(mockLogger).times(...);
PowerMock.verifyStatic(LoggerFactory.class).times(...);
}
}
如果您不想使用像 powermock 这样的框架,您可以使用以下技巧:
public class ClassUnderTest {
private Supplier<Logger> loggerSupplier = () -> getLogger(ClassUnderTest.class);
public void doSomething(Calendar gegenwart) {
if (loggerSupplier.get().isTraceEnabled()) {
// non trivial code
}
}
}
现在您可以模拟记录器了:
public class ClassUnderTestUnitTest{
@Mock
private Supplier<Mock> loggerSupplier;
@Mock
private Logger logger;
@Test
public void findeSnapshotMitLueke() {
ClassUnderTest toTestInstance = new ClassUnderTest ();
when(loggerSupplier.get()).thenReturn(logger);
when(logger.isTraceEnabled()).thenReturn(true)
toTestInstance.doSomething(Calendar.getInstance());
// verifyLogger();
}
}
在带有 slf4j 和 logback 的 spring-boot 环境中的单元测试中,我想确保 LOGGER.isTraceEnabled()
returns 仅对特定测试 class 为真.
原因是,有时我们会用 if (LOGGER.isTraceEnabled()) {...}
保护缓慢且重要的代码。在单元测试中,我们希望确保在打开跟踪时不会破坏应用程序。
被测代码:
public class ClassUnderTest{
private static final Logger LOGGER = LoggerFactory.getLogger(ClassUnderTest.class);
public void doSomething(Calendar gegenwart) {
if (LOGGER.isTraceEnabled()) {
// non trivial code
}
}
}
测试代码:
public class ClassUnderTestUnitTest{
@Test
public void findeSnapshotMitLueke() {
ClassUnderTest toTestInstance = new ClassUnderTest ();
// I want to make sure trace logging is enabled, when
// this method is executed.
// Trace logging should not be enabled outside this
// test class.
toTestInstance.doSomething(Calendar.getInstance());
}
}
您可以使用 PowerMock 轻松创建 LoggerFactory 的静态模拟,并使其 return 成为 Logger 的常规模拟(使用 EasyMock)。然后你只需定义 Logger.isTraceEnabled()
和 Logger.trace()
.
超出我的想象:
@PrepareForTest({ LoggerFactory.class })
@RunWith(PowerMockRunner.class) // assuming JUnit...
public class ClassUnderTestUnitTest{
@Test
public void findeSnapshotMitLueke() {
Logger mockLogger = EasyMock.createMock(Logger.class);
EasyMock.expect(mockLogger.isTraceEnabled()).andReturn(true);
EasyMock.expect(mockLogger.trace(any()));
EasyMock.expectLastCall().anyTimes() // as trace is a void method.
// Repeat for other log methods ...
PowerMock.mockStatic(LoggerFactory.class);
EasyMock.expect(LoggerFactory.getLogger(ClassUnderTest.class)
.andReturn(mockLogger);
PowerMock.replay(mockLogger, LoggerFactory.class);
ClassUnderTest toTestInstance = new ClassUnderTest ();
// I want to make sure trace logging is enabled, when
// this method is executed.
// Trace logging should not be enabled outside this
// test class.
toTestInstance.doSomething(Calendar.getInstance());
// After the operation if needed you can verify that the mocked methods were called.
PowerMock.verify(mockLogger).times(...);
PowerMock.verifyStatic(LoggerFactory.class).times(...);
}
}
如果您不想使用像 powermock 这样的框架,您可以使用以下技巧:
public class ClassUnderTest {
private Supplier<Logger> loggerSupplier = () -> getLogger(ClassUnderTest.class);
public void doSomething(Calendar gegenwart) {
if (loggerSupplier.get().isTraceEnabled()) {
// non trivial code
}
}
}
现在您可以模拟记录器了:
public class ClassUnderTestUnitTest{
@Mock
private Supplier<Mock> loggerSupplier;
@Mock
private Logger logger;
@Test
public void findeSnapshotMitLueke() {
ClassUnderTest toTestInstance = new ClassUnderTest ();
when(loggerSupplier.get()).thenReturn(logger);
when(logger.isTraceEnabled()).thenReturn(true)
toTestInstance.doSomething(Calendar.getInstance());
// verifyLogger();
}
}