如何解决当从jmockit使用MockUp时,即使在其他测试中拆除后也使用模拟方法
我将jmockit版本1.24与junit5一起使用,在这里我模拟了singleton类的公共方法,如下所示。
这是我的Test.java:
@Test
void myTest() {
MockUp mySingletonMock = new MockUp<MySingleton>() {
@Mock
public FileHeaders getHeader(String localFilePath) {
return new FileHeaders(checksum,"",new Date());
}
};
// Some assert statements
mySingletonMock.tearDown();
}
这是Singleton.java:
public class MySingleton {
private static MySingleton instance = new MySingleton();
private MySingleton(){
// Some initialization
}
public static MySingleton getInstance(){
return instance;
}
public FileHeaders getHeader(String localFilePath) {
...
}
}
我面对上述方法的问题,在myTest
完成执行之后执行的所有测试均失败,因为他们仍然看到模拟的getHeader
方法,而不是MySingleton类中的原始方法(我有使用调试语句验证了确实是这种情况。
如何防止在其他测试中看到这种getHeader
方法的模拟版本? (最好不更改jmockit的版本)。
所有这一切的怪异之处在于,使用maven在我的系统上本地运行的测试没有任何问题。但是当在teamcity上运行时会失败。
感谢您的帮助。谢谢。
编辑: 我尝试过的事情:
-
我尝试将
$clinit()
方法添加到MockUp中。但是没有运气。 -
我已在测试结束时通过反射将单例实例重置为新实例,如下所示。这也没有解决问题。
void resetMySingletonInstance() throws IllegalAccessException,InvocationTargetException,InstantiationException,NoSuchFieldException {
Constructor<?>[] constructors = MySingleton.class.getDeclaredConstructors();
Constructor theConstructor = constructors[0];
theConstructor.setAccessible(true);
// Verified that this gives a new instance
MySingleton instanceMySingleton = (MySingleton) theConstructor.newInstance();
Field ourInstanceField = MySingleton.class.getDeclaredField("ourInstance");
ourInstanceField.setAccessible(true);
ourInstanceField.set(null,instanceMySingleton);
}
解决方法
首先,我不会直接在测试方法中初始化和拆除模拟,而是使用setup()和tearDown()方法(@Before和@After注释)。
private List<MockUp<?>> mockUps = new ArrayList<>();
public void addMockUp(MockUp<?> mockUp) {
mockUps.add(mockUp);
}
@Before
public void setup() throws Exception {
addMockUp(new MockUp<MySingleton>() {
@Mock
public FileHeaders getHeader(String localFilePath) {
return new FileHeaders(checksum,"",new Date());
}
});
// other mocks ?
}
@Test
void myTest() {
// Some assert statements on MySingleton.getInstance()
}
@After
public void tearDown() {
mockUps.stream().forEach(mock->mock.tearDown());
}
但是测试中的问题是MySingleton是使用模拟对象初始化的。如果所有测试都在同一VM中执行,则该模拟对象将被重新用于后续测试。 我不确定为什么您在本地没有此问题,而仅在您的构建服务器上,也许是VM分叉的配置:https://maven.apache.org/surefire/maven-surefire-plugin/examples/fork-options-and-parallel-execution.html
要解决此问题,您需要找到一种在每次测试后重新初始化单例的方法。 例如,一种解决方案是更改MySingleton,使其能够在测试后重置实例。如果无法同时访问MySingleton,则可以使用例如延迟加载并在tearDown方法中将其重置。
公共类MySingleton { 私有静态MySingleton实例;
private MySingleton(){
// Some initialization
}
public static MySingleton getInstance(){
if(instance == null) {
instance = new MySingleton();
}
return instance;
}
public static void reset() {
instance = null;
}
public FileHeaders getHeader(String localFilePath) {
...
}
}
如果您无法更改生产代码以通过反射重置字段,则还有另一种选择: Set Value of Private Static Field
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。