zhuguowei
zhuguowei

Reputation: 8487

Why has @ComponentScan then DataMongoTest not work

There is a mongo dao class com.foo.bar.dao.CompanyRecommendationDao and there is a corresponding test 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

At first run the test class is's ok, but if adding the ComponentScan annotation above the Application class

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

in this case when run CompanyRecommendationDaoTest could get below error

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

So why it could load other service class, should it only load mongo related class?

From 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.

What is the difference if add @ComponentScan("com.foo") explicitly(default package is com.foo.bar)?

PS. When enable trace log

Situation 1(without @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]

Situation 2(with @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]

Upvotes: 2

Views: 2482

Answers (2)

zhuguowei
zhuguowei

Reputation: 8487

Reason:

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

Resolve:

  1. Defines exclude filters explicitly
    @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. Have a separate main class defined in the same package as the test class(e.g.CompanyRecommendationDaoTest )
    @SpringBootApplication
    public class DaoTestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DaoTestApplication.class, args);
        }
    
    }

Upvotes: 1

Ananthapadmanabhan
Ananthapadmanabhan

Reputation: 6216

The issue that you are facing might be due to @ComponentScan. Initially when you use the @DataMongotTest annotation only spring configures the beans that are necessary for running the mongo only.But when you add the component scan annotation to the main class and set the package scan level like "com.foo" spring will automatically search and find beans for registration in all packages under this path.

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

Since you are not essentially providing the entire application data including property values etc when you are running test , spring fails to create the bean for sqlSessionTemplate.java , which might be needing some property values which are not loaded in test.

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

It is a good practice to have a separate main class defined for running tests so that you can have full control over the configurations while running tests.

Refer here

Upvotes: 2

Related Questions