BackEnd/Spring

[Spring] @SpringBootTest

샤아이인 2022. 3. 7.

 

SpringBoot에서 테스트 시작하기

Spring Boot는 애플리케이션을 테스트하기 위한 많은 기능을 제공해 줍니다!

Spring boot에서 테스트 모듈은 spring-boot-test와 spring-boot-test-autoconfigure가 존재하는데,
대부분의 경우는 spring-boot-starter-test만으로도 충분하며, spring-boot-starter-test는 spring boot의 테스트에 사용되는 Starter 패키지입니다.


spring-boot-starter-test는 JUnit는 물론이고, AssertJ, Hamcrest를 포함한 여러 유용한 라이브러리를 포함하고 있습니다.

 

spring-boot-starter-test를 대부분 사용하면 테스트를 위한 라이브러리 외에도 여러 유용한 라이브러리를 포함하고 있습니다.

  • JUnit
  • Spring Test & Spring Boot Test
  • AssertJ
  • Hamcrest
  • Mockito
  • JSONassert
  • JsonPath

 

@SpringBootTest

spring-boot-test는 @SpringBootTest라는 에노테이션을 제공하고 있습니다.
@SpringBootTest 에노테이션은 테스트에 사용할 Application Context를 쉽게 생성 및 조작할 수 있으며, 이는 기존 spring-test에서 사용하던 @ContextConfiguration의 발전된 기능입니다.

 

이러한 @SpringBootTest는 매우 다양한 기능을 제공합니다!

전체 빈 중 특정 빈을 선택하여 생성한다든지, 특정 빈을 Mock으로 대체한다든지, 테스트에 사용할 프로퍼티 파일을 선택하거나 특정 속성만 추가한다든지, 특정 Configuration을 선택하여 설정할 수도 있습니다.

또한, 주요 기능으로 테스트 웹 환경을 자동으로 설정해주는 기능이 있습니다.

 

또한 Junit5 에 들어와서 부터는 @RunWith(SpringRunner.class) 를 사용하지 않아도 됩니다!

 

1. @SpringBootTest는 통합테스트를 위해 주로 사용한다!

1) 개요

  - 실제 운영 환경에서 사용될 클래스들을 통합하여 테스트 하는것을 통합테스트라 부른다.
  - 단위 테스트와 같이 기능 검증을 위한 것이 아니라 spring framework에서 전체적으로 플로우가 제대로 동작하는지 검증하기 위해 사용


2) 장점
 - 애플리케이션의 설정, 모든 Bean을 모두 로드하기 때문에 운영환경과 가장 유사한 테스트가 가능하다.
 - 전체적인 Flow를 쉽게 테스트 가능하다.

 

3) 단점
 - 애플리케이션의 설정, 모든 Bean을 모두 로드하기 때문에 시간이 오래걸리고 무겁다.
 - 테스트 단위가 크기 때문에 디버깅이 어려운 편이다.

 

2. 제공되는 기능

  • 전체 빈들 중 특정 빈을 선택하여 생성
  • 특정 빈을 Mock으로 대체
  • 테스트에 사용할 프로퍼티 파일을 선택하거나 특정 속성만 추가
  • 특정 Configuration을 선택하여 설정
  • 테스트 웹 환경을 자동으로 설정

1) Bean

@SpringBootTest 어노테이션은 classes라는 속성을 제공합니다. 해당 속성을 통해서 빈을 생성할 클래스들을 지정할 수 있습니다.

classes 속성에 @Configuration 어노테이션을 사용하는 클래스가 있다면 내부에서 @Bean 어노테이션을 통해서 생성되는 빈도 모두 등록이 됩니다.

만일 classes 속성을 통해서 클래스를 지정하지 않으면 애플리케이션 상에 정의된 모든 빈을 생성합니다.

@SpringBootTest(classes = {UserServiceImpl.class, AutoConfig.class})
public class SpingBootTestV1 {

    // Service로 등록하는 빈
    @Autowired private UserServiceImpl userServiceImpl;
    
    // AutoConfig에서 생성하는 빈
    @Autowired private RestTemplate restTemplate;
}

 

2) TestConfiguration

기존에 정의했던 Configuration을 커스터마이징하고 싶은 경우 TestConfiguration 기능을 사용할 수 있습니다!

TestConfiguration은 ComponentScan 과정에서 생성될 것이며, 자신이 속한 테스트가 실행될때 정의된 빈을 생성하여 등록됩니다.

@SpringBootTest
class ConfigTest {

    @Autowired
    Dog dog;

    @Test
    void name() {
        assertThat(dog.show()).isEqualTo("Test에서 만든 Dog 월 월!!");
    }

    @TestConfiguration
    public static class TestConfig {

        public TestConfig() {
            System.out.println("TestConfig 생성");
        }

        // Config의 Dog빈을 커스터마이징한다.
        @Bean
        public Dog testDog() {
            return new Dog("Test에서 만든 Dog");
        }
    }
}

ComponentScan을 통해서 감지되기 때문에 만일 @SpringBootTestclasses 속성을 이용하여 특정 클래스만을 지정했을 경우에는 TestConfiguation은 감지되지 않습니다.

그런 경우 classes 속성에 직접 TestConfiguration을 추가하면 됩니다!

 

하지만 더 좋은 방법은 @Import 어노테이션을 사용하는 것입니다. 

 

@Import 어노테이션을 통해서 직접 사용할 TestConfiguration을 명시할 수 있으며, 특정 테스트 클래스의 내부 클래스가 아닌 별도의 클래스로 분리하여 여러 테스트에서 공유할 수도 있습니다.

@SpringBootTest(classes = {Config.class})
@Import(TestConfig.class)
class ConfigTest {

    @Autowired
    Dog dog;

    @Test
    void name() {
        assertThat(dog.show()).isEqualTo("Test에서 만든 Dog 월 월!!");
    }
}
@TestConfiguration
public class TestConfig {

    public TestConfig() {
        System.out.println("TestConfig 생성");
    }

    // Config의 Dog빈을 커스터마이징한다.
    @Bean
    public Dog testDog() {
        return new Dog("Test에서 만든 Dog");
    }
}

 

3) MockBean

@MockBean을 사용하면 Mock 객체를 빈으로 등록할 수 있으며, @Autowired를 통해 빈을 주입시 Spring의 ApplicationContext는 Mock 객체를 주입해 줍니다!
만약 @MockBean으로 선언한 객체와 같은 이름과 티입으로 이미 빈 등록이되어있다면 선언한 Mock 빈으로 대체된다.

@SpringBootTest
public class MockBeanTest {

    @MockBean
    private Dog mockDog;

    @Test
    public void mockTest() {
        // given
        System.out.println(mockDog.getName());
        
        // when
        given(mockDog.getName()).willReturn("mockDog");
        
        // then
        System.out.println(mockDog.getName());
    }    
}

출력 결과는 다음과 같다

null
mockDog

처음 apple을 출력하면 MockBean으로 생성된 mockDog의 Name인 null을 반환한다.

이후 Mockito의 given - willReturn을 통해 Mock 객체가 리턴할 Name을 설정해준다.

mockDog의 Name이 설정된 Name으로 출력되는 것을 확인할 수 있다.

 

4. Properties

Spring Boot는 기본적으로 application.properties(혹은 application.yml)를 통해 애플리케이션 설정을 수행한다.
하지만 테스트 중 설정이 기존과 달라질 필요가 있는 경우, SpringBootTest의 properties라는 속성을 이용한다.

@SpringBootTest(properties = "classpath:application-test.yml")
public class SomeTest {
    ...
}

 

5. Web Environment

@SpringBootTest의 webEnvironment 파라미터를 이용해서 손쉽게 웹 테스트 환경을 선택할 수 있습니다. 제공하는 설정값은 아래와 같습니다.

  • MOCK
    • WebApplicationContext를 로드하며 내장된 서블릿 컨테이너가 아닌 Mock 서블릿을 제공.
    • @AutoConfigureMockMvc 어노테이션을 함께 사용하면 별다른 설정 없이 간편하게 MockMvc를 사용한 테스트를 진행할 수 있습니다.
    • @AutoConfigureMockMvc
      Mock 테스트 시 필요한 의존성을 제공해 준다.
      MockMvc 객체를 통해 실제 컨테이너가 실행되는 것은 아니지만 로직상 테스트를 진행할 수 있다.
      (DispatcherServlet을 로딩하여 Mockup으로 처리가능)
  • RANDOM_PORT
    • EmbeddedWebApplicationContext를 로드하며 실제 서블릿 환경을 구성합니다.
    • 생성된 서블릿 컨테이너는 임의의 포트를 listen
  • DEFINED_PORT
    • RAMDOM_PORT와 동일하게 실제 서블릿 환경을 구성하지만, 포트는 애플리케이션 프로퍼티에서 지정한 포트를 listen합니다(application.properties 또는 application.yml에서 지정한 포트).
  • NONE
    • 일반적인 ApplicationContext를 로드하며 아무런 서블릿 환경을 구성하지 않습니다.

 

출처

https://meetup.toast.com/posts/124

 

 

 

 

댓글