为什么 @ComponentScan 然后 DataMongoTest 不起作用

Why has @ComponentScan then DataMongoTest not work

有一个mongo道classcom.foo.bar.dao.CompanyRecommendationDao还有一个对应的测试class: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

一开始运行测试class没问题,但是如果在Application上面添加ComponentScan注解class

@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

那么为什么它可以加载其他服务 class,它应该只加载 mongo 相关的 class 吗?

来自 DataMongoTest javadoc

Can be used when a test focuses only on MongoDB components. Using this annotation will disable full auto-configuration and instead apply only configuration relevant to MongoDB tests.

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

PS。 启用跟踪日志时

情况一(没有@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]

您遇到的问题可能是由于 @ComponentScan。最初,当您使用 @DataMongotTest 注释时,仅 spring 配置 运行 mongo only.But 所需的 bean,当您将组件扫描注释添加到主class 设置包扫描级别如"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,这可能需要一些未在测试中加载的 属性 值。

Annotation that can be used in combination with @RunWith(SpringRunner.class) for a typical MongoDB test. Can be used when a test focuses only on MongoDB components. Using this annotation will disable full auto-configuration and instead apply only configuration relevant to MongoDB tests. By default, tests annotated with @DataMongoTest will use an embedded in-memory MongoDB process (if available).

为 运行 测试定义一个单独的主要 class 是一个很好的做法,这样您就可以在 运行 测试时完全控制配置。

参考here

原因:

The underlying component scan configuration of @SpringBootApplication defines exclude filters that are used to make sure slicing works as expected. If you are using an explicit @ComponentScan directive on your @SpringBootApplication-annotated class, be aware that those filters will be disabled. If you are using slicing, you should define them again.

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) })

If you directly use @ComponentScan (that is, not through @SpringBootApplication) you need to register the TypeExcludeFilter with it. See the Javadoc for details.

  1. 在与测试 class(例如CompanyRecommendationDaoTest
  2. 相同的包中定义一个单独的主要 class
    @SpringBootApplication
    public class DaoTestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DaoTestApplication.class, args);
        }
    
    }