Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot 2.1.1 : java.lang.IllegalStateException: Unable to retrieve @EnableAutoConfiguration base packages error when running unit test

The following error will be thrown when I execute my unit test. Please kindly advise whether I missed out something. I am using Spring Boot 2.1.1.RELEASE. Thanks!

java.lang.IllegalStateException: Unable to retrieve @EnableAutoConfiguration base packages


application-test.yml

spring:
  profiles: test
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
    username : xxx
    password : xxx
  jpa:
    hibernate:
      ddl-auto: update
  cache:
    type: simple

AppRepository.java

@Repository
public interface AppRepository extends CrudRepository<App, Integer> {

    App findFirstByAppId(String appId);

}   

AppRepositoryTest.java

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {AppRepository.class})
@EnableConfigurationProperties
@DataJpaTest
@ActiveProfiles("test")
public class AppRepositoryTest {

    @Autowired
    AppRepository appRepository;

    @Before
    public void setUp() throws Exception {
        App app = new App();
        app.setAppId("testId");
        appRepository.save(app);
    }

    @Test
    public void testFindFirstByAppId() {
        assertNotNull(appRepository.findFirstByAppId("testId"));        
    }
}

Package Structure

└───src
    ├───main
    │   ├───java
    │   │   └───com
    │   │       └───abc
    │   │           └───app
    │   │               ├───config
    │   │               ├───data
    │   │               │   ├───model
    │   │               │   └───repository
    │   │               ├───exception
    │   │               ├───service
    │   │               └───serviceImpl
    │   └───resources
    │       ├───META-INF
    │       └───static
    │           ├───css
    │           ├───images
    │           └───js
    └───test
        └───java
            └───com
                └───abc
                    └───app
                        ├───data
                        │   └───repository
                        ├───service
                        └───serviceImpl
like image 571
Zaccus Avatar asked Jan 08 '19 08:01

Zaccus


2 Answers

I tried the solution from Zaccus, but that didn't work for me. I am using Spring Boot 2.3.2.RELEASE and JUnit 5. For my situation, I needed to move my model and repository into a separate library because it needed to be shared by my webapp and a tool.

Below is what I got to work:

Spring Boot JPA Test without main or SpringApplication

package com.example.repository;

import com.example.model.Place;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;

import javax.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;

@DataJpaTest
@ContextConfiguration(classes={PlaceRepositoryTest.class})
@EnableJpaRepositories(basePackages = {"com.example.*"})
@EntityScan("com.example.model")
public class PlaceRepositoryTest {
    @Autowired private DataSource dataSource;
    @Autowired private JdbcTemplate jdbcTemplate;
    @Autowired private EntityManager entityManager;
    @Autowired private PlaceRepository repo;

    @Test
    void testInjectedComponentsAreNotNull(){
        assertThat(dataSource).isNotNull();
        assertThat(jdbcTemplate).isNotNull();
        assertThat(entityManager).isNotNull();
        assertThat(repo).isNotNull();
    }

    @Test
    public void testInsert() throws Exception {
        String placeName = "San Francisco";
        Place p = new Place(null, placeName);

        repo.save(p);
        Optional<Place> op = repo.findByName(placeName);

        assertThat(op.isPresent()).isTrue();
    }
}

As of Spring Boot 2.1, when using @DataJpaTest, you no longer need to specify

@ExtendWith(SpringExtension.class)
@EnableJpaRepositories(basePackages = {"com.example.*"})

For my situation, basePackages = {"com.example.*"} wasn't necessary since PlaceRepository and PlaceRepositoryTest are in the same package. I only added it here in case someone has tests which include repositories found in different packages. Without "basePackages", @EnableJpaRepositories will scan the package of the annotated configuration class for Spring Data repositories by default.

Initially, I only had the following annotations:

@DataJpaTest
@ContextConfiguration(classes={PlaceRepositoryTest.class})
@EnableJpaRepositories(basePackages = {"com.example.*"})

The websites I found said that I would only need @DataJpaTest and @EnableJpaRepositories, however, with only the above, I got the following error:

java.lang.IllegalStateException: Failed to load ApplicationContext
:
:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'placeRepository' defined in com.example.repository.PlaceRepository defined in @EnableJpaRepositories declared on PlaceRepositoryTest: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class com.example.model.Place

It took me a while to figure this out. With "Not a managed type", I thought there was something wrong with my class Place:

package com.example.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@NoArgsConstructor
@AllArgsConstructor
@Data
@Entity
public class Place {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;
    private String name;
}

The root cause is that Place was not scanned as an Entity. To fix this, I needed to add

@EntityScan("com.example.model")

I found "@EntityScan" from another solution on stackoverflow: Spring boot - Not an managed type

Below is my setup:

src
 + main
    + java
       + com.example
          + model
             + Place
          + repository
             + PlaceRepository
 + test
    + java
       + com.example
          + repository
             + PlaceRepository
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>jpa</artifactId>
    <version>1.0-SNAPSHOT</version>

    <packaging>jar</packaging>

    <properties>
        <spring.boot.starter.version>2.3.2.RELEASE</spring.boot.starter.version>
        <h2.version>1.4.200</h2.version>
        <lombok.version>1.18.12</lombok.version>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>${spring.boot.starter.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>${spring.boot.starter.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>${spring.boot.starter.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>${h2.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
package com.example.repository;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.example.model.Place;

import java.util.Optional;

@Repository
public interface PlaceRepository extends CrudRepository<Place, Long> {
    Optional<Place> findByName(String name);
}
like image 153
Pierre C. Pineda Avatar answered Sep 20 '22 12:09

Pierre C. Pineda


I managed to get it to work when I removed "ActiveProfiles" and "EnableConfigurationProperties" and finally specify the Main class in the ContextConfiguration annotation:

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {AppMain.class})
@DataJpaTest
public class AppRepositoryTest {

    @Autowired
    AppRepository appRepository;

    @Before
    public void setUp() throws Exception {
        App app = new App();
        app.setAppId("testId");
        appRepository.save(app);
    }

    @Test
    public void testFindFirstByAppId() {
        assertNotNull(appRepository.findFirstByAppId("testId"));        
    }
}
like image 33
Zaccus Avatar answered Sep 18 '22 12:09

Zaccus