programing

스프링 부트에서의 컴포넌트/빈 테스트 방법

starjava 2023. 3. 13. 20:03
반응형

스프링 부트에서의 컴포넌트/빈 테스트 방법

Spring Boot 어플리케이션에서 컴포넌트/빈을 테스트하려면 Spring Boot 매뉴얼의 테스트 부분을 참조하십시오.@Test,@SpringBootTest,@WebMvcTest,@DataJpaTest이치노
합니까?호하는방방법????????
(「 부트」등)이 테스트클래스를 ?@SpringBootTest,@WebMvcTest,@DataJpaTest무슨 일입니까?

PS: 저는 많은 개발자(경험자들도)가 다른 개발자보다 주석을 사용하는 결과를 얻지 못한다는 것을 깨달았기 때문에 이 질문을 만들었습니다.

TL-DR

  • 스프링 컨테이너를 로드하지 않고 직접 테스트할 수 있는 구성 요소에 대한 일반 단위 테스트를 작성합니다(로컬 및 CI 빌드에서 실행).

  • JPA, 컨트롤러, REST 클라이언트, JDBC 등과 같은 스프링 컨테이너를 로드하지 않고는 바로 테스트할 수 없는 컴포넌트에 대한 부분 통합 테스트/슬라이싱 유닛 테스트를 작성합니다(로컬 및 CI 빌드에서 실행).

  • 값을 가져오는 일부 고급 구성 요소에 대한 전체 통합 테스트(엔드 투 엔드 테스트)를 작성합니다(CI 빌드에서 실행).


컴포넌트를 테스트하는 3가지 주요 방법

  • 일반 장치 테스트(스프링 컨테이너를 장착하지 않음)
  • 완전 통합 테스트(모든 구성과 콩이 포함된 스프링 컨테이너 로드)
  • 부분 통합 테스트/테스트 슬라이스(Spring 컨테이너에 매우 제한된 구성과 콩을 장착)

모든 컴포넌트를 다음 3가지 방법으로 테스트할 수 있습니까?

스프링을 사용한 일반적인 방법은 통합 테스트에서 모든 구성 요소를 테스트할 수 있으며 일부 구성 요소만 (용기 없이) 단일 테스트에 적합합니다.
그러나 스프링 유무에 관계없이 단일 및 통합 테스트는 반대하지 않고 상호 보완적입니다.

컴포넌트를 (스프링 없이) 플레인 테스트 할 수 있는지 스프링만으로 테스트할 수 있는지 판별하는 방법

컴포넌트/메서드가 스프링 기능을 사용하여 논리를 실행하지 않기 때문에 스프링 컨테이너로부터 종속성이 없는 테스트 대상 코드를 인식할 수 있습니다.
가져가세요.FooService :::

@Service
public class FooService{

   private FooRepository fooRepository;
   
   public FooService(FooRepository fooRepository){
       this.fooRepository = fooRepository;
   }

   public long compute(...){
      List<Foo> foos = fooRepository.findAll(...);
       // core logic
      long result = 
           foos.stream()
               .map(Foo::getValue)
               .filter(v->...)
               .count();
       return result;
   }
}

FooService는 스프링을 실행할 필요가 없는 계산과 로직을 수행합니다.
compute()되어 있습니다.
하는 데 거예요.FooRepository Boot Spring 에서 데이터 JPA 컨텍스트 your Spring Boot( 부트)를 설정합니다.FooRepository기본 구현 및 기타 여러 가지 기능을 제공합니다.
컨트롤러(휴대 또는 MVC) 테스트도 마찬가지입니다.
Spring 없이 컨트롤러를 엔드포인트에 바인드하려면 어떻게 해야 합니까?어떻게 하면 컨트롤러가 스프링 없이 HTTP 요구를 해석하고 HTTP 응답을 생성할 수 있을까요?을 사용하다

1) 플레인 유닛 테스트 작성

애플리케이션에서 스프링 부트를 사용한다고 해서 실행하는 테스트 클래스에 스프링 컨테이너를 로드할 필요가 있는 것은 아닙니다.
스프링 컨테이너에서 종속성이 필요 없는 테스트를 작성하므로 테스트 클래스에 스프링을 사용하거나 로드할 필요가 없습니다.
Spring을 사용하는 대신 테스트할 클래스를 인스턴스화하고 필요한 경우 모의 라이브러리를 사용하여 테스트 대상 인스턴스를 종속성에서 분리합니다.
테스트한 컴포넌트의 분리에 유리하고 속도가 빠르기 때문에 이 방법을 따를 수 있습니다.
에서는 단위 줍니다.FooService상기의 클래스.
놀리면 돼FooRepository를 할 수 FooService.
JUnit 5 모키토

import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;


@ExtendWith(MockitoExtension.class)
class FooServiceTest{

    FooService fooService;  

    @Mock
    FooRepository fooRepository;

    @BeforeEach 
    void init{
        fooService = new FooService(fooRepository);
    }

    @Test
    void compute(){
        List<Foo> fooData = ...;
        Mockito.when(fooRepository.findAll(...))
               .thenReturn(fooData);
        long actualResult = fooService.compute(...);
        long expectedResult = ...;
        Assertions.assertEquals(expectedResult, actualResult);
    }

}

2) 완전 통합 테스트 작성

엔드 투 엔드 테스트를 작성하려면 응용 프로그램의 전체 구성과 콩을 포함하는 컨테이너를 로드해야 합니다.
이를 실현하는 방법은 다음과 같습니다.

주석은 Spring Application을 통해 테스트에서 사용되는 ApplicationContext를 작성함으로써 작동합니다.

다음과 같이 사용하여 모의 테스트 없이 테스트할 수 있습니다.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.junit.jupiter.api.Test;

@SpringBootTest
public class FooTest {

   @Autowired
   Foo foo;

   @Test
   public void doThat(){
      FooBar fooBar = foo.doThat(...);
      // assertion...
   }    
   
}

하지만 이치에 맞는다면 용기의 콩을 조롱할 수도 있습니다.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.context.SpringBootTest;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

@SpringBootTest
public class FooTest {

   @Autowired
   Foo foo;

   @MockBean
   private Bar barDep;

   @Test
   public void doThat(){
      Mockito.when(barDep.doThis()).thenReturn(...);
      FooBar fooBar = foo.doThat(...);
      // assertion...
   }    
   
}

.Bar클래스)org.mockito.MockBarorg.springframework.boot.test.mock.mockito.MockBean주석)을 클릭합니다.

완전한 통합 테스트는 CI 빌드에 의해 실행되어야 합니다.

풀 스프링 콘텍스트를 로드하려면 시간이 걸립니다. 때문에 가 있습니다.@SpringBootTest이로 인해 유닛 테스트 실행이 매우 길어질 수 있으며 일반적으로 개발자의 머신 로컬 빌드와 테스트 작성을 쾌적하고 효율적으로 하기 위해 중요한 테스트 피드백의 속도를 크게 늦추고 싶지 않습니다.
따라서 일반적으로 개발자의 기계에서는 "저속" 테스트가 실행되지 않습니다.
통합테스트연동테스트)를.IT가 서픽스Test테스트 클래스의 이름 지정에 서픽스를 붙이고, 이러한 서픽스가 연속적인 통합 빌드에서만 실행되도록 합니다.
그러나 Spring Boot은 어플리케이션의 많은 것(나머지 컨트롤러, MVC 컨트롤러, JSON 시리얼화/디시리얼라이제이션, 지속성 등)에서 동작하기 때문에 CI 빌드에서만 실행되는 많은 유닛 테스트를 작성할 수 있으며 이 테스트도 적절하지 않습니다.
엔드 투 엔드 테스트를 CI 빌드에서만 실행하는 것은 좋지만 지속성, 컨트롤러 또는 JSON 테스트를 CI 빌드에서만 실행하는 것은 전혀 문제가 없습니다.
실제로 개발자 빌드는 빠릅니다만, 로컬에서의 테스트 실행은 가능한 퇴행의 극히 일부만을 검출합니다.
이 경고를 방지하기 위해 Spring Boot에서는 중간 방법인 부분 연동 테스트 또는 슬라이스 테스트(일명 슬라이스 테스트)가 제공됩니다.음음음포포포다다다

3) 슬라이스 테스트에 의한 특정 레이어 또는 우려 사항에 초점을 맞춘 부분 적분 테스트 작성

"일반적으로 테스트할 수 있는 테스트 인식(스프링 없음)" 요지에서 설명한 바와 같이 일부 구성요소는 실행 중인 용기를 통해서만 테스트할 수 있습니다.
왜 ㅇㅇㅇㅇㅇ를 쓰죠?@SpringBootTest이러한 컴포넌트를 테스트하기 위해 몇 가지 특정 구성 클래스와 콩만 로드하면 되는 반면 애플리케이션의 모든 콩과 구성을 로드합니다.
예를 들어 컨트롤러 부품을 테스트하기 위해 완전한 Spring JPA 컨텍스트(빈, 구성, 메모리 데이터베이스 등)를 로드하는 이유는 무엇입니까?
반대로 스프링 컨트롤러와 관련된 모든 구성과 콩을 로드하여 JPA 저장소 부분을 테스트하는 이유는 무엇입니까?
Spring Boot는 슬라이스 테스트 기능을 통해 이 점에 대처합니다.
이러한 테스트 속도는 일반 유닛 테스트(용기 없음)만큼 빠르지 않지만 스프링 컨텍스트 전체를 로드하는 것보다 훨씬 빠릅니다.따라서 로컬 머신에서 실행하는 것은 일반적으로 매우 적합합니다.
각 슬라이스 테스트 플레이버는 요건에 따라 필요에 따라 변경할 수 있는 매우 제한된 자동 구성 클래스 세트를 로드합니다.

일반적인 슬라이스 테스트 기능:

오브젝트 JSON의 시리얼화 및 시리얼화가 올바르게 동작하고 있는지 테스트하려면 @JsonTest 주석을 사용합니다.

MVC 하려면 Spring MVC를 합니다.@WebMvcTest석입니니다다

Spring 하려면 Spring WebFlux 를 합니다.@WebFluxTest석입니니다다

.@DataJpaTest주석을 사용하여 JPA 애플리케이션을 테스트합니다.

스프링 부츠
상세한 것에 대하여는, 메뉴얼의 테스트 부분을 참조해 주세요.
삽입 테스트 슬라이스 주석이 처리하지 않는 특정 콩 세트를 로드해야 할 경우 자체 테스트 슬라이스 주석(https://spring.io/blog/2016/08/30/custom-test-slice-with-spring-boot-1-4))을 작성할 수도 있습니다.

4) 빈 초기화 지연으로 특정 콩을 중심으로 부분통합 테스트 작성

얼마 전 다른 콩에 의존하는 여러 콩에 의존하는 서비스 콩을 부분 통합으로 테스트하는 경우를 본 적이 있습니다.문제는 두 개의 깊은 의존관계 콩이 일반적인 이유(http 요청과 데이터베이스에 대용량 데이터가 있는 쿼리)로 인해 조롱당해야 한다는 것이었습니다.
Spring Boot 컨텍스트를 모두 로드하면 오버헤드가 발생하므로 특정 콩만 로드하려고 했습니다.위해서 시험 .@SpringBootTest요.classes합니다.
여러 번 시도했지만 효과가 있을 것 같은 것을 얻을 수 있었습니다만, 포함할 콩/구성의 중요한 리스트를 정의하지 않으면 안 되었습니다.
그것은 정말 깔끔하지도 유지보수가 불가능했다.
보다 대안으로 .2: Spring Boot 2.2에서 bean .

@SpringBootTest(properties="spring.main.lazy-initialization=true")
public class MyServiceTest { ...}

런타임에 사용되는 콩만 로드할 수 있는 장점이 있습니다.
저는 그 속성을 사용하는 것이 테스트 수업에서 표준이 될 필요는 없다고 생각합니다만, 특정 테스트의 경우에는 그것이 올바른 방법으로 나타납니다.

언급URL : https://stackoverflow.com/questions/51789880/how-to-test-a-component-bean-in-spring-boot

반응형