使用Mockito.mockStatic编写JUnit测试批量执行失败单独运行成功问题咨询
问题根因
Java虚拟机的类加载机制规定:在同一个类加载器的生命周期内,同一个类只会被加载、初始化一次。你写的Host类的LOCALHOST、IP两个静态属性是在类初始化阶段(静态代码块)一次性完成赋值的,批量执行测试时:
- 第一个测试用例第一次调用
Host的静态方法时,就触发了Host类的初始化,静态属性直接被赋值为当前InetAddress的返回结果 - 后续所有测试用例再调用
Host的方法,拿到的都是第一次初始化好的静态属性值,你后续对InetAddress的mock完全不会生效,自然执行失败
单独执行测试时,每个测试都会启动独立的类加载上下文,Host类每次都会重新初始化,所以不会出现问题。
可行解决方案
方案1:修改Host类实现(更推荐,符合可测试性设计,同时适配运行时动态变化的场景)
移除静态初始化块,改为每次调用方法时实时获取地址信息,修改后的Host代码如下:
import java.net.InetAddress; import java.net.UnknownHostException; public class Host { public static String getLOCALHOST() { try { return InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { return "Unkown hostname"; } } public static String getIP() { try { return InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { return "Unkown ip"; } } }
修改完业务代码后,你原有的测试代码不需要做任何调整,批量执行就能全部通过。
方案2:不修改业务代码,测试时强制重置Host类状态(适合无法改动业务代码的场景)
借助反射在每个测试执行前清空Host类的静态属性,或者使用PowerMock强制类重新加载:
如果使用PowerMock,只需要在测试类上添加以下注解即可,无需调整原有测试逻辑:
@RunWith(PowerMockRunner.class) @PrepareForTest({Host.class, InetAddress.class}) class HostTest { // 原有测试方法保持不变 }
内容的提问来源于stack exchange,提问作者Josip
相关产品推荐
相关产品推荐

