替换实例化类的实现而不涉及代码(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如何用测试实现替换实际类