为什么@ComponentScan然后DataMongoTest无法工作

时间:2019-06-02 15:09:32

标签: spring-boot spring-data-mongodb spring-test

有一个mongo dao类com.foo.bar.dao.CompanyRecommendationDao和一个相应的测试类:com.foo.bar.dao.CompanyRecommendationDaoTest

@RunWith(SpringRunner.class)
@DataMongoTest(includeFilters = @ComponentScan.Filter(type= FilterType.ASSIGNABLE_TYPE,value={CompanyRecommendationDao.class}))
@Import(SpringMongoConfig.class)
public class CompanyRecommendationDaoTest

首先运行测试类是可以的,但是如果在Application类之上添加ComponentScan注释

@SpringBootApplication
@ComponentScan("com.foo")
public class BarApplication 

在这种情况下,运行CompanyRecommendationDaoTest可能会出现以下错误

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'companyManagementService': Unsatisfied dependency expressed through field 'companyMapper'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'companyMapper' defined in file [/Users/zhugw/develop/workspace/bar/target/classes/com/foo/bar/mapper/CompanyMapper.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required

那么为什么它可以加载其他服务类,而应该只加载与mongo相关的类呢?

来自DataMongoTest javadoc

  

当测试仅针对MongoDB组件时可以使用。   使用此注释将禁用完全自动配置,而仅应用与MongoDB测试相关的配置。

如果显式添加@ComponentScan(“ com.foo”)(默认包是com.foo.bar)有什么区别?

PS。 启用跟踪日志时

情况1(没有@ComponnetScan)

2019-06-02 22:28:08.876 TRACE 13875 --- [           main] o.s.c.a.ClassPathBeanDefinitionScanner   : Scanning file [/Users/zhugw/develop/workspace/foo/bar/target/classes/com/foo/bar/dao/CompanyRecommendationDao.class]
2019-06-02 22:28:08.877 TRACE 13875 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'org.springframework.boot.test.context.filter.TestTypeExcludeFilter'
2019-06-02 22:28:08.877 TRACE 13875 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'org.springframework.boot.test.autoconfigure.filter.TypeExcludeFilters'
2019-06-02 22:28:08.877 DEBUG 13875 --- [           main] o.s.c.a.ClassPathBeanDefinitionScanner   : Identified candidate component class: file [/Users/zhugw/develop/workspace/foo/bar/target/classes/com/foo/bar/dao/CompanyRecommendationDao.class]

情况2(使用@ComponnetScan)

2019-06-02 22:40:23.989 TRACE 14573 --- [           main] o.s.c.a.ClassPathBeanDefinitionScanner   : Scanning file [/Users/zhugw/develop/workspace/foo/bar/target/classes/com/foo/bar/dao/CompanyRecommendationDao.class]
2019-06-02 22:40:23.989 DEBUG 14573 --- [           main] o.s.c.a.ClassPathBeanDefinitionScanner   : Identified candidate component class: file [/Users/zhugw/develop/workspace/foo/bar/target/classes/com/foo/bar/dao/CompanyRecommendationDao.class]

2 个答案:

答案 0 :(得分:1)

您面临的问题可能是由于@ComponentScan引起的。最初,当您使用@DataMongotTest批注时,仅spring会配置仅运行mongo所必需的bean。但是,当您将组件扫描批注添加到主类并像"com.foo" spring这样设置程序包扫描级别时,会自动在此路径下的所有软件包中搜索并查找要注册的bean。

Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required

由于在运行测试时实际上并没有提供整个应用程序数据,包括属性值等,因此spring无法为sqlSessionTemplate.java创建bean,这可能需要一些未在测试中加载的属性值。

  

可以与   @RunWith(SpringRunner.class)用于典型的MongoDB测试。可以使用   当测试仅针对MongoDB组件时。使用此注释   将禁用完全自动配置,而仅适用   与MongoDB测试相关的配置。默认情况下,带注释的测试   使用@DataMongoTest时将使用嵌入式内存MongoDB进程(如果   可用)。

最好为运行测试定义一个单独的主类,以便您可以在运行测试时完全控制配置。

引用here

答案 1 :(得分:0)

原因:

  

@SpringBootApplication的基础组件扫描配置定义了排除过滤器,这些过滤器用于确保切片按预期工作。如果在@SpringBootApplication注释的类上使用显式的@ComponentScan指令,请注意这些过滤器将被禁用。如果使用切片,则应重新定义它们。

     

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html

解决:

  1. 定义明确排除过滤器
    @ComponentScan(value="com.foo",excludeFilters = { @ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class) })

  

如果直接使用@ComponentScan(即,不是通过@SpringBootApplication),则需要向其中注册TypeExcludeFilter。有关详细信息,请参见Javadoc。

  1. 在与测试类(例如CompanyRecommendationDaoTest)相同的包中定义了单独的主类
    @SpringBootApplication
    public class DaoTestApplication {

        public static void main(String[] args) {
            SpringApplication.run(DaoTestApplication.class, args);
        }

    }