我有遗漏的代码,我不想碰。
public class LegacyCode{
public LegacyCode() {
Service s = new ClassA();
s.getMessage();
}
}
ClassA
提供CORBA服务呼叫的地方。
public class ClassA implements Service{
@Override
public String getMessage() {
// Make CORBA service call...
return "Class A";
}
}
界面Service
看起来像;
public interface Service {
String getMessage();
}
出于测试目的,我想用存根替换Service
(LegacyCode
实现的ClassA
)的实现。
public class ClassB implements Service {
@Override
public String getMessage() {
return "Stub Class B";
}
}
到目前为止一切顺利。但是,如果在显示的遗留代码中没有任何修改,可以在ClassB
的实例化时加载ClassA
而不是ClassA
吗?
// In my test workbench
new LegacyCode(); // "Stub Class B"
我尝试编写自定义类加载器并在应用程序启动时通过java vm参数加载它,但只有第一个类(此处为LegacyCode
)由该加载器加载。
提前致谢
答案 0 :(得分:3)
使用PowerMock
可以为构造函数代码创建模拟(或存根)。答案取自this link。我会尝试将其转换为与您的用例完全匹配:
@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassA.class)
public class LegacyTester {
@Test
public void testService() {
// Inject your stub
PowerMock.createMock(ClassA.class);
Service stub = new MyServiceStub();
PowerMock.expectNew(ClassA.class).andReturn(stub);
PowerMock.replay(stub, ClassA.class);
// Implement test logic here
LegacyCode legacyCode = new LegacyCode();
// Implement Test steps
// Call verify if you want to make sure the ClassA constructor was called
PowerMock.verify(stub, ClassA.class)
}
}
这样,您可以在调用ClassA
构造函数时注入存根,而无需更改旧代码。希望这就是你所需要的。
答案 1 :(得分:1)
AspectJ的一种方式。我同意Hovercraft,这是依赖注入的一个很好的例子,但如果你不能改变源代码,AspectJ可能是你的首选工具。
这比我更好地解释了AspectJ案例:Can AspectJ replace "new X" with "new SubclassOfX" in third-party library code?
答案 2 :(得分:0)
更简单的方法是在测试代码中创建ClassA
。在最初在实际代码中找到的相同包中声明它并使用相同的方法名称。只是让方法什么也不做。
例如,如果您的项目结构如下所示:
+- src
+- main
+- java
+- com.company.code
-- LegacyCode.java
-- Service.java
+- com.company.code.service
-- ClassA.java
+- test
+- java
+- com.company.code
-- LegacyCodeTest.java
在ClassA
下创建另一个/src/test/java/com/company/code/
:
package com.company.code.service;
/** Replaces the original implementation for testing purposes */
public class ClassA implements Service{
@Override
public String getMessage() {
return "I replaced the original implementation";
}
}
现在您的项目结构将如下所示:
+- src
+- main
+- java
+- com.company.code
-- LegacyCode.java
-- Service.java
+- com.company.code.service
-- ClassA.java
+- test
+- java
+- com.company.code
-- LegacyCodeTest.java
+- com.company.code.service
-- ClassA.java
执行单元测试后,将加载ClassA
文件夹中的test
。这比使用模拟框架简单得多,特别是如果您的旧代码很乱,而不是依赖注入友好且实际的ClassA
在任何地方都使用。
请记住,这种策略可能会使您的测试代码更加模糊,并且您无法测试ClassA
本身的实际实现,也无法轻松地为不同的测试场景提供替代实现。 / p>