如何测试自己具有自动装配依赖关系的 Spring 服务 bean?

Posted

技术标签:

【中文标题】如何测试自己具有自动装配依赖关系的 Spring 服务 bean?【英文标题】:How to test Spring service beans that themself have autowired dependencies? 【发布时间】:2014-06-22 18:09:37 【问题描述】:

我想测试一些他们自己包含其他自动装配服务的服务。但是测试本身不需要这些“外部”服务。

如何创建测试设置,例如以下示例?

package de.myapp.service;

@Service
public class MyServiceDelegator 
    @Autowired
    private List<ServiceInterface> services;

    public ServiceInterface delegate(String id) 
        //routine to find the right ServiceInterface based on the given id
    



@Service
public class MyService implements ServiceInterface 



@Service
public class MyCustomService implements ServiceInterface 
    //that is the problem during testing
    @Autowired
    private de.myapp.repository.SomeDao dao;



@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("applicationContext.xml")
public class ServiceDelegatorTest 
    @Autowired
    private ApplicationContext ac

    @Test
    public void testDelegator() 
        MyServiceDelegator dg = ac.getBean(MyServiceDelegator.class);
        ac.delegate("test");
    

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan  base-package="de.myapp.service" />
</beans>

问题:所有包含来自未在JUnit 测试中扫描的包的自动装配依赖项的服务(如MyCustomService)都会抛出异常:

原因: org.springframework.beans.factory.NoSuchBeanDefinitionException: 否 为依赖找到了类型为 [SomeDao] 的合格 bean:预计在 至少 1 个有资格作为自动装配候选者的 bean 依赖。依赖注解: @org.springframework.beans.factory.annotation.Autowired(required=true) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1103) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:963) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858) 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480) ... 57 更多

【问题讨论】:

你在使用SpringJUnit4ClassRunner吗? 是的,见上面的@RunWith(SpringJUnit4ClassRunner.class) 啊,不好意思,同班一起跑,错过了。 通常的方法是创建一个application-text.xml 来定义测试所需的额外bean。由于某种原因这不可行吗? 【参考方案1】:

您可以使用Springockito 将模拟服务实现添加到您的测试应用程序上下文中。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mockito="http://www.mockito.org/spring/mockito"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                       http://www.springframework.org/schema/beans/spring-beans.xsd
                       http://www.springframework.org/schema/context
                       http://www.springframework.org/schema/context/spring-context.xsd"
                       http://www.mockito.org/spring/mockito
                       http://www.mockito.org/spring/mockito.xsd">

    <context:component-scan  base-package="de.myapp.service" />

    <mockito:mock id="dao" class="de.myapp.repository.SomeDao" />

</beans>

【讨论】:

这是一个完美的框架!是否也可以用它来模拟@Value注解?【参考方案2】:

问题在于SomeDao 没有被组件扫描拾取,因为它不在de.myapp.service 包下。

您已经明确声明组件扫描的包是de.myapp.service

我建议您进行以下更改:

&lt;context:component-scan base-package="de.myapp" /&gt;

这样de.myapp下的所有代码都可以进行组件扫描。

如果您想避免在组件扫描中包含所有代码,您可以执行以下操作:

<context:component-scan base-package="de.myapp.service, de.myapp.repository" /> 

【讨论】:

我试图避免扩展包扫描,因为SomeDao 本身将包含另一个注入的依赖项,该依赖项具有另一个依赖项,该依赖项具有另一个依赖项,可能具有仅在网络服务器应用程序上下文(如 ContextCloseListener 或类似名称)。我不认为扫描我的整个应用程序是测试单个需求的好解决方案... 是的,谢谢,但问题仍然存在,因为存储库 bean 在这里也只是一个示例:任何 bean 都可能包含当前扫描上下文之外的任何其他 bean。所以我必须添加所有的 spring 服务,这很困难,因为其中一些将依赖于 webserver、数据库配置等。 我明白你的意思。但是如果你想要真正的集成测试,你必须以某种方式包含依赖bean。这将使用组件扫描、XML 或 Java Config(可能与 Spring Profiles 一起)来完成

以上是关于如何测试自己具有自动装配依赖关系的 Spring 服务 bean?的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 测试不会自动装配所有依赖项

Spring学习总结-自动装配

SpringBean自动装配

Spring框架参考手册(4.2.6版本)翻译——第三部分 核心技术 6.4.5 自动装配

具有 JPA 依赖关系的 Flyway Spring Boot Autowired Bean

2018-03-30 装配bean之自动化装配