我正在尝试为aproject实现单元测试,它使用遗留的“实用程序”项目,这个项目充满了静态方法,许多类都是最终的,或者它们的方法是最终的。我根本无法更新遗留项目。
JMock和EasyMock都扼杀了最终方法,我没有看到测试静态调用的好方法。有哪些技术可以测试这些?
答案 0 :(得分:27)
如果您能够重构代码,可以使用简单的实例方法将调用包装到final / static方法中,例如:
protected Foo doBar(String name) {
return Utility.doBar(name);
}
这允许您在单元测试中覆盖您的包装器方法以返回Foo的模拟实例。
或者你可以使用Powermock,它扩展了Easymock(和Mockito),允许模拟最终和静态方法:
PowerMock是一个框架,可以扩展其他模拟库,例如EasyMock,具有更强大的功能。 PowerMock使用自定义类加载器和字节码操作来模拟静态方法,构造函数,最终类和方法,私有方法,删除静态初始化器等等。
这是一个模拟静态最终方法的example测试,该示例显示了如何模拟其他类型:
@Test
public void testMockStaticFinal() throws Exception {
mockStatic(StaticService.class);
String expected = "Hello altered World";
expect(StaticService.sayFinal("hello")).andReturn("Hello altered World");
replay(StaticService.class);
String actual = StaticService.sayFinal("hello");
verify(StaticService.class);
assertEquals("Expected and actual did not match", expected, actual);
// Singleton still be mocked by now.
try {
StaticService.sayFinal("world");
fail("Should throw AssertionError!");
} catch (AssertionError e) {
assertEquals("\n Unexpected method call sayFinal(\"world\"):",
e.getMessage());
}
}
答案 1 :(得分:6)
间接/依赖注入级别怎么样?
由于旧版实用程序项目是您的依赖项,因此请创建一个接口以将其与代码分开。现在,此接口的实际/生产实现委托给遗留实用程序方法。
public LegacyActions : ILegacyActions
{
public void SomeMethod() { // delegates to final/static legacy utility method }
}
对于测试,您可以创建此接口的模拟,并避免与旧版实用程序交互。
答案 2 :(得分:3)
JMockit允许您模拟静态方法和最终类。我假设它使用了一些classloadin-fu,虽然我还没有真正研究过它。
JMockit Expectations API允许 期望被设定在任何一种 方法调用(在接口上, 抽象类,具体的最终或 非最终类,静态 方法),以及课堂上 通过任何实例化 构造
答案 3 :(得分:2)
正如已经指出的那样,可以使用JMockit。 一个例子:
@Test
public void mockStaticAndFinalMethods(@Mocked LegacyService mock) {
new Expectations() {{
LegacyService.staticMethod("hello"); result = "Hello altered World";
}};
String actual = LegacyService.staticMethod("hello");
new LegacyService().finalMethod(123, "test");
assertEquals("Hello altered World", actual);
new Verifications() {{
mock.finalMethod(123, "test"); // verify this call occurred at least once
}};
}
答案 4 :(得分:1)
如果你的非重构方法使用类似JNDI的东西连接到另一个服务,我会考虑启动一个JDNI服务并用你控制的存根填充它。这是一种痛苦,但相对简单。它可能意味着设置一个数据库或JMS监听器或其他什么,但应该有一个轻量级的java实现,你可以放入测试。
答案 5 :(得分:-1)
如果需要,JMock和JDave可以模拟最终的方法和类。 Here 是指示。话虽如此,我会将这些遗留代码(正如其他人已经建议的那样)视为外部依赖,并构建接口并模拟这些代码。它是另一层间接,但由于你不能改变遗留代码,它似乎是合理的。