Spring Boot test не запускает контекст или загружает зависимости - PullRequest
2 голосов
/ 07 апреля 2020

Очень начинающая проблема, но я не могу пройти мимо. У меня есть основное приложение Spring Boot c и одно хранилище Spring Data MongoDB, которое подключается к экземпляру облачного атласа. Проблема в том, что в моем тесте Spring Boot мой репозиторий не подключен автоматически, а встроенный экземпляр MongoDB не создается. Если я запускаю приложение Spring Boot и в основном классе я автоматически подключаю репозиторий, это работает. Почему это не работает в моем тесте?

Это мой тестовый класс:

@DataMongoTest
@ExtendWith(SpringExtension.class)
public class SampleServiceTest{


    @Autowired
    private SampleRepository sampleRepository;

    @Test
    public void shouldCreateSample(){
        sampleRepository.save(new Sample());
    }
}

Это мой пом. xml:

<?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">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath></relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>



    <groupId>com.comand</groupId>
    <artifactId>business-owner-service</artifactId>
    <version>1.0-SNAPSHOT</version>
    <description>API Gateway</description>

    <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>de.flapdoodle.embed</groupId>
            <artifactId>de.flapdoodle.embed.mongo</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-parent</artifactId>
                <version>Greenwich.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

1 Ответ

3 голосов
/ 07 апреля 2020

Когда вы используете аннотацию @Autowired, в основном вы сопоставляете переменную с объектом, который существует в контексте приложения. Помните, что контекст приложения создается при запуске приложения весенней загрузки. Все классы с аннотацией @Service, @Repository, @Component создаются в контексте приложения.

Я предполагаю, что SampleRepository имеет одну из следующих аннотаций: @Service, @Repository @Component @Repository. И когда вы запускаете приложение весенней загрузки, создается контекст приложения и создается экземпляр класса SampleRepository.

Аннотация @Autowire сопоставит объект, созданный в контексте приложения, с переменной, которая имеет аннотация @Autowire.

Причина, по которой он не работает в вашем тесте, заключается в том, что объект класса SampleRepository не существует. И вы не можете сопоставить его с переменной, которую вы аннотировали @Autowire.

. Это можно исправить двумя способами:

  1. Первое решение - создать контекст приложения, когда Вы запускаете тестовый класс. Я предлагаю не загружать весь контекст приложения со всеми объектами, которые были созданы. Будет лучше загрузить только ту часть контекста приложения, которая необходима в вашем тестовом классе.
@EnableConfigurationProperties(SampleRepository.class)
   public class TestConfiguration {
}

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = { TestConfiguration.class })
public class SampleServiceTest{
}
Второе решение - изменить аннотацию @DataMongoTest, как показано ниже:
@DataMongoTest(includeFilters = @Filter(Service.class))
//or
@DataMongoTest(includeFilters = @Filter(Component.class))

Использование аннотации @DataMongoTest отключит полную автоконфигурацию и вместо этого будет применять только конфигурацию, относящуюся к тестам MongoDB. Таким образом, классы, отмеченные @Services, Component, не создаются. includeFilters - это набор фильтров, которые можно использовать для добавления фильтрованных bean-компонентов в контекст приложения.

Я подозреваю, что вы аннотировали класс SampleRepository аннотацией @Service или @Component, и это почему он не создал экземпляр класса SampleRepository.

Я посмотрел ваш код в git репо и изменил, как показано ниже:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class BusinessOwnerServiceTest {

    @Autowired
    private BusinessOwnerService businessOwnerService;

    @Autowired
    private BusinessOwnerRepository businessOwnerRepository;

    @Test
    public void shouldCreateNewBusinessOwner(){
       businessOwnerService.findBusinessOwnerByEmail("EMAIL@gmail.com");    
    }

}

Ниже приведен результат: enter image description here

Ниже приведено второе решение:

@RunWith(SpringJUnit4ClassRunner.class)
@DataMongoTest(includeFilters = @Filter(Service.class))
public class BusinessOwnerServiceTest {

    @Autowired
    private BusinessOwnerService businessOwnerService;

    @Autowired
    private BusinessOwnerRepository businessOwnerRepository;

    @Test
    public void shouldCreateNewBusinessOwner(){
       businessOwnerService.findBusinessOwnerByEmail("EMAIL@gmail.com");    
    }

}

Ниже приводится результат второго решения: enter image description here

...