替换实例化类的实现而不涉及代码(java)
我有我不想碰的遗留代码替换实例化类的实现而不涉及代码(java),java,unit-testing,constructor,dependency-injection,classloader,Java,Unit Testing,Constructor,Dependency Injection,Classloader,我有我不想碰的遗留代码 public class LegacyCode{ public LegacyCode() { Service s = new ClassA(); s.getMessage(); } } 其中ClassA提供CORBA服务调用 public class ClassA implements Service{ @Override public String getMessage() { // Mak
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";
}
}
界面服务
如下所示
public interface Service {
String getMessage();
}
出于测试目的,我想用存根替换ClassA
实现的Service
(在LegacyCode
中)的实现
public class ClassB implements Service {
@Override
public String getMessage() {
return "Stub Class B";
}
}
到目前为止还不错。但是,在所示的遗留代码处不进行任何修改就可以在实例化ClassA
时加载ClassB
而不是ClassA
// In my test workbench
new LegacyCode(); // "Stub Class B"
我试图编写一个自定义类加载器,并在应用程序启动时通过JavaVM参数加载它,但该加载器只加载了第一个类(这里是LegacyCode
)
提前感谢一种方法是使用AspectJ。我同意Hovercraft,这是一个很好的依赖注入案例,但是如果您不能更改源代码,AspectJ可能是您选择的工具
这比我能更好地解释AspectJ案例:使用
PowerMock
可以为构造函数代码创建一个模拟(或存根)。答案来自于。我将尝试将其转换为与您的用例完全匹配:
@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
构造函数时,就可以注入存根,而不必更改遗留代码。希望这就是您所需要的。简单的方法是在测试代码中创建一个ClassA
。在实际代码中最初找到的相同包中声明它,并使用相同的方法名。让这个方法什么都不做
例如,如果项目结构如下所示:
+- src
+- main
+- java
+- com.company.code
-- LegacyCode.java
-- Service.java
+- com.company.code.service
-- ClassA.java
+- test
+- java
+- com.company.code
-- LegacyCodeTest.java
+- 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
在/src/test/java/com/company/code/
下创建一个备选ClassA
:
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
+- 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
执行单元测试时,将加载test
文件夹中的ClassA
。这比使用模拟框架要简单得多,尤其是当旧代码凌乱、不支持依赖项注入且实际的ClassA
到处使用时
请记住,这种策略会使您的测试代码更加模糊,您无法测试
ClassA
本身的实际实现,也无法为不同的测试场景轻松提供替代实现。最好从一开始就使用依赖项注入。那么这些问题就没有意义了。谢谢你的回答。不幸的是,现有代码(许多类)目前没有提供此功能。我们不希望在没有新业务需求的情况下进行这些修改。但是我们需要在不使用CORBA调用的情况下测试代码。这是用于单元测试的吗?如果是这样,您可以使用power mock进行测试。如果是这样的话,请告诉我,我会解释怎么做。这种方法叫存根吗?JUnit如何用测试实现替换实际类