Spring

Spring Boot 테스트가 컨텍스트를 시작하지 않거나 종속성을 로드하지 않음

기록만이살길 2023. 1. 19. 12:07
반응형

Spring Boot 테스트가 컨텍스트를 시작하지 않거나 의존성을 로드하지 않음 질문하다

1. 질문(문제점):

매우 초보적인 문제지만 지나칠 수 없는 문제입니다. 기본 Spring Boot 앱과 클라우드 아틀라스 인스턴스에 연결하는 Spring Data MongoDB 리포지토리 하나가 있습니다. 문제는 내 Spring Boot 테스트에서 내 리포지토리가 자동 연결되지 않고 포함된 MongoDB 인스턴스가 생성되지 않는다는 것입니다. Spring Boot 앱을 시작하고 기본 클래스에서 리포지토리를 autowire하면 작동합니다. 테스트에서 작동하지 않는 이유는 무엇입니까?

이것은 내 테스트 클래스입니다.

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


    @Autowired
    private SampleRepository sampleRepository;

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

이것은 내 pom.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>

2. 해결방안:

어노테이션 을 사용하면 @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{
}
  1. @DataMongoTest 두 번째 솔루션은 아래와 같이 어노테이션을 수정하는 것입니다.
@DataMongoTest(includeFilters = @Filter(Service.class))
//or
@DataMongoTest(includeFilters = @Filter(Component.class))

어노테이션을 사용하면 @DataMongoTest전체 자동 구성이 비활성화되고 대신 MongoDB 테스트와 관련된 구성만 적용됩니다. 따라서 어노테이션이 달린 클래스 @ServicesComponent인스턴스화되지 않습니다. includeFilters응용 프로그램 컨텍스트에 필터링된 빈을 추가하는 데 사용할 수 있는 필터 집합입니다.

나는 당신이 또는 어노테이션으로 클래스 SampleRepository에 어노테이션을 달았으며 그것이 클래스 의 인스턴스를 생성하지 않은 이유라고 생각합니다 .@Service@ComponentSampleRepository

git repo에서 코드를 살펴보고 아래와 같이 수정했습니다.

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

    @Autowired
    private BusinessOwnerService businessOwnerService;

    @Autowired
    private BusinessOwnerRepository businessOwnerRepository;

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

}

그 아래에 결과가 있습니다. 여기에 이미지 설명 입력

그 아래에는 두 번째 솔루션이 있습니다.

@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");    
    }

}

아래는 두 번째 솔루션의 결과입니다. 여기에 이미지 설명 입력

반응형