Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why is spring boot's DataJpaTest scanning @Component

Confident this hasn't been asked but reading through the Spring docs and testing utilities I found this annotation and thought I'd start using it. Reading through the fine print I read:

Regular @Component beans will not be loaded into the ApplicationContext.

That sounded good and I even liked the idea of using H2 except from what I found the entity I wanted to use had catalog and schema modifiers to it and the default H2 I couldn't figure out how to support that. I made an H2 datasource for the test branch and use that and override the replace. I wound up with

@RunWith(SpringRunner.class)
@ContextConfiguration(classes=ABCH2Congfiguration.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE)
public class StatusRepositoryTest {

}

However my tests fails fro Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type. which leads to: Error creating bean with name 'customerServiceImpl': Unsatisfied dependency.

However the customerServiceImpl is this bean:

@Component
public class CustomerServiceImpl  implements CustomerService {
}

That says @Component. The fine print for DataJpaTest says it doesn't load @Components. Why is it doing that and thus failing the test?

As Kyle and Eugene asked below here's the rest:

package com.xxx.abc.triage;
@Component
public interface CustomerService {
}

Configuration
@ComponentScan("com.xxx.abc")
@EnableJpaRepositories("com.xxx.abc")
//@Profile("h2")
public class ABMH2Congfiguration {

    @Primary
    @Bean(name = "h2source")
    public DataSource dataSource() {
        EmbeddedDatabase build = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).setName("ABC").addScript("init.sql").build();
        return build;
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter bean = new HibernateJpaVendorAdapter();
        bean.setDatabase(Database.H2);
        bean.setShowSql(true);
        bean.setGenerateDdl(true);
        return bean;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
        LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
        bean.setDataSource(dataSource);
        bean.setJpaVendorAdapter(jpaVendorAdapter);
        bean.setPackagesToScan("com.xxx.abc");
        return bean;
    }

    @Bean
    public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
        return new JpaTransactionManager(emf);
    }

}

And just to clarify the question, why is @Component being loaded into the context within a @DataJpaTest?

like image 345
Michael Sampson Avatar asked Jul 25 '17 16:07

Michael Sampson


People also ask

Why do we need component scan in Spring?

One of the most important annotations in spring is @ComponentScan which is used along with the @Configuration annotation to specify the packages that we want to be scanned. @ComponentScan without arguments tells Spring to scan the current package and all of its sub-packages.

Does Spring boot require component scan?

By default, the @ComponentScan annotation will scan for components in the current package and all its sub-packages. So if your application doesn't have a varying package structure then there is no need for explicit component scanning.

What is the use of @DataJpaTest?

@DataJpaTest is used to test JPA repositories. It is used in combination with @RunWith(SpringRunner. class) . The annotation disables full auto-configuration and applies only configuration relevant to JPA tests.

What is component scan annotation in Spring?

With Spring, we use the @ComponentScan annotation along with the @Configuration annotation to specify the packages that we want to be scanned. @ComponentScan without arguments tells Spring to scan the current package and all of its sub-packages.


2 Answers

@ComponentScan automatically inject all found @Component and @Service into context. You could override it by separate @Bean:

@Bean
CustomerService customerService{
    return null;
}

Or remove @Component annotation from CustomerService and CustomerServiceImpl, but you should add @Bean at your production @Configuration

like image 190
Eugene Ustimenko Avatar answered Oct 16 '22 23:10

Eugene Ustimenko


@DataJpaTest does not load @Component, @Service... by default, only @Repository and internal things needed to configure Spring data JPA.

In your test, you can load any @Configuration you need, and in your case, you load @ABMH2Congfiguration which performs a @ComponentScan that's why Spring try to load your CustomerService.

You should only scanning the @Repository in this configuration class, and scan others @Component, @Service... in another @Configuration like DomainConfiguration. It's always a good practice to separate different types of configurations.

like image 28
Farid Mesnata Avatar answered Oct 16 '22 22:10

Farid Mesnata