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?
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.
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.
@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.
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.
@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
@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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With