使用 JMockit 模拟和验证 SLF4J
Mocking and verifying SLF4J with JMockit
我有一个 class,SLF4J 记录器的实例如下:
public class MyClass {
private static final Logger log = LoggerFactory.getLogger(MyClass.class);
public void foo() {
log.warn("My warn");
}
}
而且我需要使用 JMockit 对其进行测试,例如:
@Test
public void shouldLogWarn(@Mocked Logger log) throws Exception {
new Expectations() {{
log.warn(anyString);
}};
MyClass my = new MyClass();
my.foo();
}
经过大量搜索后我发现,我需要以某种方式使用 MockUp。但是不知道具体是怎样的。
顺便说一句,我使用的是最新版本的 JMockit(1.29),您不能再为最终静态字段 setField(log)。
JMockit 具有适用于这种情况的 @Capturing
注释
Indicates a mock field or a mock parameter for which all classes extending/implementing the mocked type will also get mocked.
Future instances of a capturing mocked type (ie, instances created sometime later during the test) will become associated with the mock field/parameter. When recording or verifying expectations on the mock field/parameter, these associated instances are regarded as equivalent to the original mocked instance created for the mock field/parameter.
这意味着如果您使用 @Capturing
而不是 @Mocked
对其进行注释,则在测试 运行 期间创建的每个 Logger
都将与您注释的一个相关联.所以以下工作:
@Test
public void shouldLogWarn(@Capturing final Logger logger) throws Exception {
// This really ought to be a Verifications block instead
new Expectations() {{
logger.warn(anyString);
}};
MyClass my = new MyClass();
my.foo();
}
附带说明一下,如果您只想验证是否调用了方法,最好改用 Verifications,因为这正是它的目的。所以你的代码看起来像这样:
@Test
public void shouldLogWarn(@Capturing final Logger logger) throws Exception {
MyClass my = new MyClass();
my.foo();
new Verifications() {{
logger.warn(anyString);
}};
}
或者,您可以在 Logger
和 LoggerFactory
上使用 @Mocked
在某些情况下,@Capturing
由于注释工作方式的复杂性,无法按预期工作。幸运的是,您也可以通过在 Logger
和 LoggerFactory
上使用 @Mocked
来获得相同的效果,如下所示:
@Test
public void shouldLogWarn(@Mocked final LoggerFactory loggerFactory, @Mocked final Logger logger) throws Exception {
MyClass my = new MyClass();
my.foo();
new Verifications() {{
logger.warn(anyString);
}};
}
注意: JMockit 1.34 到 1.38 has a bug 阻止它与 slf4j-log4j12
一起工作,可能还有 SLF4J 的其他依赖项。如果您 运行 遇到此错误,请升级到 1.39 或更高版本。
我有一个 class,SLF4J 记录器的实例如下:
public class MyClass {
private static final Logger log = LoggerFactory.getLogger(MyClass.class);
public void foo() {
log.warn("My warn");
}
}
而且我需要使用 JMockit 对其进行测试,例如:
@Test
public void shouldLogWarn(@Mocked Logger log) throws Exception {
new Expectations() {{
log.warn(anyString);
}};
MyClass my = new MyClass();
my.foo();
}
经过大量搜索后我发现,我需要以某种方式使用 MockUp。但是不知道具体是怎样的。
顺便说一句,我使用的是最新版本的 JMockit(1.29),您不能再为最终静态字段 setField(log)。
JMockit 具有适用于这种情况的 @Capturing
注释
Indicates a mock field or a mock parameter for which all classes extending/implementing the mocked type will also get mocked.
Future instances of a capturing mocked type (ie, instances created sometime later during the test) will become associated with the mock field/parameter. When recording or verifying expectations on the mock field/parameter, these associated instances are regarded as equivalent to the original mocked instance created for the mock field/parameter.
这意味着如果您使用 @Capturing
而不是 @Mocked
对其进行注释,则在测试 运行 期间创建的每个 Logger
都将与您注释的一个相关联.所以以下工作:
@Test
public void shouldLogWarn(@Capturing final Logger logger) throws Exception {
// This really ought to be a Verifications block instead
new Expectations() {{
logger.warn(anyString);
}};
MyClass my = new MyClass();
my.foo();
}
附带说明一下,如果您只想验证是否调用了方法,最好改用 Verifications,因为这正是它的目的。所以你的代码看起来像这样:
@Test
public void shouldLogWarn(@Capturing final Logger logger) throws Exception {
MyClass my = new MyClass();
my.foo();
new Verifications() {{
logger.warn(anyString);
}};
}
或者,您可以在 Logger
和 LoggerFactory
上使用 @Mocked
在某些情况下,@Capturing
由于注释工作方式的复杂性,无法按预期工作。幸运的是,您也可以通过在 Logger
和 LoggerFactory
上使用 @Mocked
来获得相同的效果,如下所示:
@Test
public void shouldLogWarn(@Mocked final LoggerFactory loggerFactory, @Mocked final Logger logger) throws Exception {
MyClass my = new MyClass();
my.foo();
new Verifications() {{
logger.warn(anyString);
}};
}
注意: JMockit 1.34 到 1.38 has a bug 阻止它与 slf4j-log4j12
一起工作,可能还有 SLF4J 的其他依赖项。如果您 运行 遇到此错误,请升级到 1.39 或更高版本。