如何通过 JMockit 和 Logger 接口使用动态部分模拟?
How to use dynamic partial mocking with JMockit and Logger interface?
我一直在使用 JMockit 和它公认的陡峭的学习曲线。我对一般的嘲笑还很陌生,所以请原谅我的无知。
我正在尝试模拟 Logger 接口,以便我可以验证 catch 语句是否正常工作。将此称为理解 JMockit 工作原理的练习。 Logger 接口的实现 class 是 Log4jLoggerAdapter 所以我想如果我将它的一个实例传递到我的 Expectations() 块中,JMockit 将使用动态部分模拟和 "see" 我的记录器语句。相反,我收到以下错误:
mockit.internal.MissingInvocation:缺少调用:org.slf4j.impl.Log4jLoggerAdapter#error(String msg, Throwable t)
Class正在测试
public class MyLoggedClass {
private static final Logger LOGGER = LoggerFactory.getLogger(MyLoggedClass.class);
... // Other variables
@Override
public void connect() {
String info = getServiceInfo();
try {
connector = MyConnectionFactory.connect(info);
} catch (Exception e) {
LOGGER.error("Exception connecting to your service with: " + info, e);
}
}
... // Other methods
}
我的@Test
public class MyLoggedClassTest {
@Tested
MyLoggedClass myLoggedClass;
@Test
public void myLoggingTest(@Mocked final Log4jLoggerAdapter logger){
new Expectations(MyConnectionFactory.class, logger){{
MyConnectionFactory.connect(anyString);
result = new Exception();
logger.error(anyString, (Throwable)any);
}};
myLoggedClass.connect();
}
我会详细介绍我尝试过的其他方法,但此页面会变成一本书。这是我最好的方法。有什么想法吗?
* 更新 *(是的,很快)
我将 @Mocked 更改为 @Cascading 并从我的 Expectations 签名中删除了记录器字段并且它起作用了。我不明白为什么。有人可以提供解释吗?摸索直到你偶然发现一些有用但你不理解的东西并不是成功的秘诀。见下文:
@Test
public void myLoggingTest(@Cascading final Log4jLoggerAdapter logger){
new Expectations(MyConnectionFactory.class){{
MyConnectionFactory.connect(anyString);
result = new Exception();
logger.error(anyString, (Throwable)any);
}};
myLoggedClass.connect();
}
在这种情况下不需要部分模拟,只需以通常的方式模拟 MyConnectionFactory
。唯一棘手的部分是如何模拟实现 Logger
接口的 class,考虑到它是从静态 class 初始化器实例化的。碰巧的是,模拟 API 中有一个功能(使用 JMockit 1.14):
public class MyLoggedClassTest
{
@Tested MyLoggedClass myLoggedClass;
@Test
public void myLoggingTest(
@Mocked MyConnectionFactory conFac,
@Capturing final Logger logger)
{
new Expectations() {{
MyConnectionFactory.connect(anyString);
result = new Exception();
}};
myLoggedClass.connect();
new Verifications() {{
logger.error(anyString, (Throwable)any);
}};
}
}
使用 @Capturing
模拟类型,任何实现 class 都会被模拟,因此测试不需要了解 Log4jLoggerAdapter
.
我一直在使用 JMockit 和它公认的陡峭的学习曲线。我对一般的嘲笑还很陌生,所以请原谅我的无知。
我正在尝试模拟 Logger 接口,以便我可以验证 catch 语句是否正常工作。将此称为理解 JMockit 工作原理的练习。 Logger 接口的实现 class 是 Log4jLoggerAdapter 所以我想如果我将它的一个实例传递到我的 Expectations() 块中,JMockit 将使用动态部分模拟和 "see" 我的记录器语句。相反,我收到以下错误:
mockit.internal.MissingInvocation:缺少调用:org.slf4j.impl.Log4jLoggerAdapter#error(String msg, Throwable t)
Class正在测试
public class MyLoggedClass {
private static final Logger LOGGER = LoggerFactory.getLogger(MyLoggedClass.class);
... // Other variables
@Override
public void connect() {
String info = getServiceInfo();
try {
connector = MyConnectionFactory.connect(info);
} catch (Exception e) {
LOGGER.error("Exception connecting to your service with: " + info, e);
}
}
... // Other methods
}
我的@Test
public class MyLoggedClassTest {
@Tested
MyLoggedClass myLoggedClass;
@Test
public void myLoggingTest(@Mocked final Log4jLoggerAdapter logger){
new Expectations(MyConnectionFactory.class, logger){{
MyConnectionFactory.connect(anyString);
result = new Exception();
logger.error(anyString, (Throwable)any);
}};
myLoggedClass.connect();
}
我会详细介绍我尝试过的其他方法,但此页面会变成一本书。这是我最好的方法。有什么想法吗?
* 更新 *(是的,很快)
我将 @Mocked 更改为 @Cascading 并从我的 Expectations 签名中删除了记录器字段并且它起作用了。我不明白为什么。有人可以提供解释吗?摸索直到你偶然发现一些有用但你不理解的东西并不是成功的秘诀。见下文:
@Test
public void myLoggingTest(@Cascading final Log4jLoggerAdapter logger){
new Expectations(MyConnectionFactory.class){{
MyConnectionFactory.connect(anyString);
result = new Exception();
logger.error(anyString, (Throwable)any);
}};
myLoggedClass.connect();
}
在这种情况下不需要部分模拟,只需以通常的方式模拟 MyConnectionFactory
。唯一棘手的部分是如何模拟实现 Logger
接口的 class,考虑到它是从静态 class 初始化器实例化的。碰巧的是,模拟 API 中有一个功能(使用 JMockit 1.14):
public class MyLoggedClassTest
{
@Tested MyLoggedClass myLoggedClass;
@Test
public void myLoggingTest(
@Mocked MyConnectionFactory conFac,
@Capturing final Logger logger)
{
new Expectations() {{
MyConnectionFactory.connect(anyString);
result = new Exception();
}};
myLoggedClass.connect();
new Verifications() {{
logger.error(anyString, (Throwable)any);
}};
}
}
使用 @Capturing
模拟类型,任何实现 class 都会被模拟,因此测试不需要了解 Log4jLoggerAdapter
.