Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring test with @DataJpaTest can't autowire class with @Repository (but with interface repository works!)

I'm trying to understand why I can't autowire a class repository but I can autowire a interface repository in the same package for the same test. The same repository works as expected when I start the application.

First, the error:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.app.person.repository.PersonRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultPersonbleBeanFactory.raiseNoMatchingBeanFound(DefaultPersonbleBeanFactory.java:1493)
    at org.springframework.beans.factory.support.DefaultPersonbleBeanFactory.doResolveDependency(DefaultPersonbleBeanFactory.java:1104)
    at org.springframework.beans.factory.support.DefaultPersonbleBeanFactory.resolveDependency(DefaultPersonbleBeanFactory.java:1066)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
    ... 28 more

I have a very simple example. The test:

@RunWith(SpringRunner.class)
@DataJpaTest
public class PersonRepositoryTest {

    @Autowired
    private PersonRepository personRepository; // fail...

    @Autowired
    private PersonCrudRepository personCrudRepository; // works!

    @Test
    public void findOne() {
    }
}

The repository class:

@Repository
public class PersonRepository {
    //code
}

The repository interface:

@Repository
public interface PersonCrudRepository extends CrudRepository<Person, Long> {
}

After a bad experience with this same error, I'm trying to find some detail in my configuration or test what is responsible for this problem. Another possibility is the @DataJpaTest does not have support for class repositories.

like image 493
Dherik Avatar asked Jan 19 '18 18:01

Dherik


People also ask

What is the use of @repository annotation?

Spring @Repository annotation is used to indicate that the class provides the mechanism for storage, retrieval, search, update and delete operation on objects.

What is @entity annotation in spring boot?

The @Entity annotation specifies that the class is an entity and is mapped to a database table. The @Table annotation specifies the name of the database table to be used for mapping.

What is no repository bean?

Annotation Type NoRepositoryBean This will typically be used when providing an extended base interface for all repositories in combination with a custom repository base class to implement methods declared in that intermediate interface.

What is 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. By default, tests annotated with @DataJpaTest use an embedded in-memory database.


1 Answers

I think I was right about the problem. After find a post on Github and read the Spring Documentation:

@DataJpaTest can be used if you want to test JPA applications. By default it will configure an in-memory embedded database, scan for @Entity classes and configure Spring Data JPA repositories. Regular @Component beans will not be loaded into the ApplicationContext.

My PersonRepository is considered a regular @Component, because it is not a Spring Data JPA repository (the interface is). So, it is not loaded.

The alternative solution is to use @SpringBootTest instead of @DataJpaTest.

The disadvantage with this solution is that will load all your context while running your test and, with this, disabling the test slicing. But do the job.

Another option, still using @DataJpaTest, is include a @Repository filter annotation, like this:

@DataJpaTest(includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Repository.class))
like image 184
Dherik Avatar answered Oct 22 '22 23:10

Dherik