Mockito.mockConstruction 在测试中提供空记录器 class
Mockito.mockConstruction provides null logger in the tested class
我想测试 Utility#fromJson 方法。为此,我需要模拟其中包含一些 JNDI 代码的 LoggerBean 构造函数。:
public class Utility {
private static Logger log = LoggerBean.getLoggerBean().getLogger(Utility.class);
private static ObjectMapper mapper = new ObjectMapper();
public static <T> T fromJson(String json, Class<T> type) {
try {
return mapper.readValue(json, type);
} catch (IOException e) {
//during test log is null here
log.error("json deserialization failed", e);
}
return null;
}
}
在下面的测试中 class 我可以使用 mockito 模拟构造函数并希望模拟的 Logger 应该出现在实用程序中 class。但是,在测试期间,实用程序 class 中的日志为空。
class UtilityTest {
@Test
void testFromJson() throws Exception {
// mocking constructor
try (MockedConstruction<LoggerBean> mocked = Mockito.mockConstruction(LoggerBean.class, (mock, context) -> {
// further stubbings ...
when(mock.getLogger(getClass())).thenReturn(Logger.getLogger(getClass()));
})) {
// the logger here works
// Logger logger = Logger.getLogger(getClass());
//logger.info("-----------------");
String json = " {\"key\":\"k1\",\"value\":\"v1\"}";
assertNotNull(Utility.fromJson(json, Tuple.class));
}
}
}
我正在使用 mockito-inline 版本 3.11.2。
请建议如何在实用程序中获取模拟日志 class。
一个明显的非答案:甚至不要尝试。
如果您真的绝对想要一个 静态方法 ,那么为什么不创建一个小实用程序 class 在 非静态方法中做同样的事情 方式(然后你可以使用那个 class 的构造函数来插入你的依赖项)。然后也许并为您的静态方法保留 class 的静态实例。
请记住,static
有很多缺点。特别是在这种情况下:如果您不做所有这些额外的工作就无法测试这个静态实用程序代码,那么您只是引入了一些会干扰单元测试的任何代码,这些代码将 use静态方法。
换句话说:您创建了难以测试的代码。现在你正面临着后果,你的答案是拿起工具箱中最大的锤子。但是用 螺丝 敲入墙壁,是的,这是可能的,但很少是个好主意。相反,你拿起钉子,或者你用螺丝刀,而是一把螺丝刀。
真正的解决方案:退后一步,记住仅在生产代码中只使用 static
,这样做 不会 干扰您正确执行任务的能力,体面,简单单元测试。
其他读者:请不要将此回答视为气馁,请给出正确的技术答案!
所以我终于意识到没有必要模拟 LoggerBean 的构造函数,以便以下工作:
private static Logger log = LoggerBean.getLoggerBean().getLogger(Utility.class);
因此 Mockito.mock(LoggerBean.class) 已经跳过了对构造函数的调用。
class UtilityTest {
private static Logger log = LoggerBean.getLoggerBean().getLogger(UtilityTest.class);
@Test
void testFromJson() throws Exception {
try (MockedStatic<LoggerBean> mockedStaticLoggerBean = Mockito.mockStatic(LoggerBean.class)) {
LoggerBean loggerBeanMocked = Mockito.mock(LoggerBean.class);
when(loggerBeanMocked.getLogger(Utility.class)).thenReturn(pp);
mockedStaticLoggerBean.when(() -> LoggerBean.getLoggerBean()).thenReturn(loggerBeanMocked);
String json = " {\"key\":\"k1\",\"value\":\"v1\"}";
assertNotNull(Utility.fromJson(json, Tuple.class));
}
}
}
现在 Utility#fromJson 将从 UtilityTest class 获取记录器。
我想测试 Utility#fromJson 方法。为此,我需要模拟其中包含一些 JNDI 代码的 LoggerBean 构造函数。:
public class Utility {
private static Logger log = LoggerBean.getLoggerBean().getLogger(Utility.class);
private static ObjectMapper mapper = new ObjectMapper();
public static <T> T fromJson(String json, Class<T> type) {
try {
return mapper.readValue(json, type);
} catch (IOException e) {
//during test log is null here
log.error("json deserialization failed", e);
}
return null;
}
}
在下面的测试中 class 我可以使用 mockito 模拟构造函数并希望模拟的 Logger 应该出现在实用程序中 class。但是,在测试期间,实用程序 class 中的日志为空。
class UtilityTest {
@Test
void testFromJson() throws Exception {
// mocking constructor
try (MockedConstruction<LoggerBean> mocked = Mockito.mockConstruction(LoggerBean.class, (mock, context) -> {
// further stubbings ...
when(mock.getLogger(getClass())).thenReturn(Logger.getLogger(getClass()));
})) {
// the logger here works
// Logger logger = Logger.getLogger(getClass());
//logger.info("-----------------");
String json = " {\"key\":\"k1\",\"value\":\"v1\"}";
assertNotNull(Utility.fromJson(json, Tuple.class));
}
}
}
我正在使用 mockito-inline 版本 3.11.2。 请建议如何在实用程序中获取模拟日志 class。
一个明显的非答案:甚至不要尝试。
如果您真的绝对想要一个 静态方法 ,那么为什么不创建一个小实用程序 class 在 非静态方法中做同样的事情 方式(然后你可以使用那个 class 的构造函数来插入你的依赖项)。然后也许并为您的静态方法保留 class 的静态实例。
请记住,static
有很多缺点。特别是在这种情况下:如果您不做所有这些额外的工作就无法测试这个静态实用程序代码,那么您只是引入了一些会干扰单元测试的任何代码,这些代码将 use静态方法。
换句话说:您创建了难以测试的代码。现在你正面临着后果,你的答案是拿起工具箱中最大的锤子。但是用 螺丝 敲入墙壁,是的,这是可能的,但很少是个好主意。相反,你拿起钉子,或者你用螺丝刀,而是一把螺丝刀。
真正的解决方案:退后一步,记住仅在生产代码中只使用 static
,这样做 不会 干扰您正确执行任务的能力,体面,简单单元测试。
其他读者:请不要将此回答视为气馁,请给出正确的技术答案!
所以我终于意识到没有必要模拟 LoggerBean 的构造函数,以便以下工作:
private static Logger log = LoggerBean.getLoggerBean().getLogger(Utility.class);
因此 Mockito.mock(LoggerBean.class) 已经跳过了对构造函数的调用。
class UtilityTest {
private static Logger log = LoggerBean.getLoggerBean().getLogger(UtilityTest.class);
@Test
void testFromJson() throws Exception {
try (MockedStatic<LoggerBean> mockedStaticLoggerBean = Mockito.mockStatic(LoggerBean.class)) {
LoggerBean loggerBeanMocked = Mockito.mock(LoggerBean.class);
when(loggerBeanMocked.getLogger(Utility.class)).thenReturn(pp);
mockedStaticLoggerBean.when(() -> LoggerBean.getLoggerBean()).thenReturn(loggerBeanMocked);
String json = " {\"key\":\"k1\",\"value\":\"v1\"}";
assertNotNull(Utility.fromJson(json, Tuple.class));
}
}
}
现在 Utility#fromJson 将从 UtilityTest class 获取记录器。