【问题标题】:Injecting a stub service inplaced of an autowired bean for unit testing注入一个替换自动装配 bean 的存根服务以进行单元测试
【发布时间】:2026-01-25 22:45:01
【问题描述】:

鉴于这个类:

 public SomeClass implements SomeInterface {

      @Autowired private RemoteService rService;

 }

并给出这个单元测试:

 public SomeClassTest {

 ...
 SomeClass sc = (SomeClass) ctx.getbean("someService");
 ..
 }

我想用其他对象来存根“rService”。我不想修改SomeInterface 方法来公开任何getter/setter,因为“rService”仅适用于一种实现。

【问题讨论】:

  • 如果你想拥有一个完整的 ApplicationContext,你所做的并不是真正的单元测试,而是集成测试

标签: java spring unit-testing dependency-injection autowired


【解决方案1】:

除了通过测试中的setter注入重置RemoteService的模拟/存根之外:

someClass.setRemoteService( remoteServiceMock );

(如果由于某种原因上述方法对您不起作用...)=>您可以创建一个“test-config.xml”,其中您要重新定义的唯一 bean 是 remoteService 具有相同(真实) bean 名称,但具有存根实现,因此它可以覆盖真正的 bean:

<bean id="remoteService" class="org.your.package.remote.RemoteServiceStub"/>

其中RemoteServiceStub 将扩展RemoteService,因此它可以按类型自动连接到SomeClass

然后在您的测试中,像往常一样注入 SomeClass:

@ContextConfiguration(locations = { "classpath:/path/to/test-config.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public class MyBeanTest {

    @Autowired
    private SomeClass someClass;

    @Test
    public void someClassShouldBehave() {
        ...
    }
}

【讨论】:

    【解决方案2】:

    将 setter 添加到实现类 (SomeClass),并手动调用 setter。这就是依赖注入的重点,以及拥有实现和接口的优势:您可以向实现中添加无法通过接口获得的方法。

    您不应该为类的单元测试使用 Spring 上下文。

    顺便说一句,getBean 方法可能会为您的类返回一个代理,而不是 SomeClass 实例。

    SomeClass sc = new SomeClass();
    sc.setRemoteService(mockRemoteService);
    // test any method of sc.
    

    【讨论】:

    • +1 - 如果您需要处理 Spring 上下文,那么您就在集成领域。这很好,@tolitius 有你的解决方案。如果添加 setter 冒犯了您,只需删除 private 关键字即可使您的 RemoteService 字段包可见。