본문 바로가기
Dev/Spring Boot

[스프링 부트 개념과 활용] 테스트

by dev_jsk 2020. 8. 24.
728x90
반응형

기본 설정

(1) pom.xml 에 의존성 추가

// pom.xml
// scope = test 로 설정
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

(2) SampleController.javaSampleService.java 작성

// SampleController.java
@RestController
public class SampleController {
    @Autowired
    private SampleService sampleService;

    @GetMapping(value="/hello")
    public String hello() {
        return "hello" + sampleService.getName();
    }
}

// SampleService.java
@Service
public class SampleService {
    public String getName() {
        return "Jinseo";
    }
}

 

@SpringBootTest

@SpringBootTest는 동작 시 @SpringBootApplication을 찾아서 필요한 모든 Bean을 스캔, 등록한다.

(1) 기본적인 형태

// SampleControllerTest.java

@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleControllerTest {
    ...
}

 

(2) WebEnvironment

MOCK

// SampleControllerTest.java

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) -> 내장 Tomcat 미사용
@AutoConfigureMockMvc
public class SampleControllerTest {
    @Autowired
    MockMvc mockMvc;	// MockMvc 사용

    @Test
    public void hello() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/hello"))
            .andExpect(MockMvcResultMatchers.status().isOk())
            .andExpect(MockMvcResultMatchers.content().string("helloJinseo"))
            .andDo(MockMvcResultHandlers.print());
    }
}

RANDOM_PORT, DEFINED_PORT, NONE

// SampleControllerTest.java
// DEFINED_PORT 의 경우도 내장 Tomcat을 사용하지만 정의된 포트값을 사용하고
// RANDOM_PORT 의 경우는 사용가능한 포트값을 사용하기 때문에 해당 방법을 추천한다.
// NONE 의 경우는 서블릿 환경을 제공하지 않는다.

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -> 내장 Tomcat 사용
public class SampleControllerTest {
    @Autowired
    TestRestTemplate testRestTemplate;	// TestRestTemplate 사용

    @Test
    public void hello() throws Exception {
        String result = testRestTemplate.getForObject("/hello", String.class);
        assertThat(result).isEqualTo("helloJinseo");
    }
}

 

@MockBean

ApplicationContext에 들어있는 Bean을 Mock으로 만든 Bean으로 교체하며 모든 @Test마다 자동으로 리셋된다.

// SampleControllerTest.java
// 위 테스트 방법의 문제점을 해결하기 위한 @MockBean 사용
// 문제점 : 테스트 시 모든 Bean 을 등록하여 테스팅 환경이 무거워진다.

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleControllerTest {
    @Autowired
    TestRestTemplate testRestTemplate;

    @MockBean
    SampleService mockSampleService;

    @Test
    public void hello() throws Exception {
        when(mockSampleService.getName()).thenReturn("jsk");

        String result = testRestTemplate.getForObject("/hello", String.class);
        assertThat(result).isEqualTo("hello jsk");
    }
}

 

* JDK11 @MockBean Error

// pom.xml
// spring-boot-starter-test 내 Mockito 말고 2.22.0 버전 추가
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.22.0</version>
</dependency>

 

WebTestClient

RestClient동기화(Synchronous) 방식으로 요청을 하나 보내면 응답이 올 때 까지 기다렸다 다시 보낼 수 있는데 WebTestClient비동기화(Asynchronous) 방식으로 요청을 보내고 응답이 오면 그 응답에 맞는 콜백이 동작하여 응답을 기다리지 않고 요청을 계속 보낼 수 있다.

// SampleControllerTest.java

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleControllerTest {
    @Autowired
    WebTestClient webTestClient;

    @MockBean
    SampleService mockSampleService;

    @Test
    public void hello() throws Exception {
        when(mockSampleService.getName()).thenReturn("jsk");

        webTestClient.get().uri("/hello").exchange().expectStatus().isOk()
            .expectBody(String.class).isEqualTo("hellojsk");
    }
}

 

슬라이스 테스트

레이어 별로 잘라서 테스트 하는 방법

  • @JsonTest
  • @WebMvcTest
  • @WebFluxTest
  • @DataJpaTest
  • ...

 

테스트 유틸

  • OutputCapture
  • TestPropertyValues
  • TestRestTemplate
  • ConfigFileApplicationContextInitializer

OutputCapture 예시

// OutputCapture : 로그 뿐만 아니라 콘솔에 출력되는 모든걸 캡쳐한다.
// SampleControllerTest.java

@RunWith(SpringRunner.class)
@WebMvcTest(SampleController.class)
public class SampleControllerTest {

    @Rule
    public OutputCapture outputCapture = new OutputCapture();

    @MockBean
    SampleService mockSampleService;

    @Autowired
    MockMvc mockMvc;

    @Test
    public void hello() throws Exception {
        when(mockSampleService.getName()).thenReturn("jsk");

        mockMvc.perform(MockMvcRequestBuilders.get("/hello"))
            .andExpect(MockMvcResultMatchers.content().string("hellojsk"));

        assertThat(outputCapture.toString())
            .contains("holoman")
            .contains("skip");
    }
}

// SampleController.java

@RestController
public class SampleController {

    Logger logger = LoggerFactory.getLogger(SampleController.class);

    @Autowired
    private SampleService sampleService;

    @GetMapping(value="/hello")
    public String hello() {
        logger.info("holoman");
        System.out.println("skip");
        return "hello" + sampleService.getName();
    }
    
}
// Result
2020-08-25 10:49:12.429  INFO 15352 --- [main] me.jsk.sample.SampleController: holoman
skip
728x90
반응형

댓글