개발강의정리/Spring

[스프링 부트 개념과 활용] 4-6. 테스트

nineDeveloper 2019. 10. 29.
728x90

스프링 부트 개념과 활용

4. 스프링 부트 활용

포스팅 참조 정보

GitHub

공부한 내용은 GitHub에 공부용 Organizations에 정리 하고 있습니다

해당 포스팅에 대한 내용의 GitHub 주소

실습 내용이나 자세한 소스코드는 GitHub에 있습니다
포스팅 내용은 간략하게 추린 핵심 내용만 포스팅되어 있습니다

https://github.com/freespringlecture/springboot-concept-uses/tree/chap04-06-test

 

freespringlecture/springboot-concept-uses

백기선님의 스프링 부트 개념과 활용 강의 내용 정리. Contribute to freespringlecture/springboot-concept-uses development by creating an account on GitHub.

github.com

해당 포스팅 참고 인프런 강의

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/dashboard

 

스프링 부트 개념과 활용 - 인프런

스프링 부트의 원리 및 여러 기능을 코딩을 통해 쉽게 이해하고 보다 적극적으로 사용할 수 있는 방법을 학습합니다. 중급 프레임워크 및 라이브러리 Spring Spring Boot 온라인 강의

www.inflearn.com

실습 환경

  • Java Version: Java 11
  • SpringBoot Version: 2.1.2.RELEASE

6. 테스트

테스트환경 구성

main 패키지 테스트 코드 작성

SampleController.class

@RestController
public class SampleController {

    @Autowired
    private SampleService sampleService;

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

SampleService.class

@Service
public class SampleService {
    public String getName() {
        return "freelife";
    }
}

test 패키지 테스트 코드 작성

SampleControllerTest.class

@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {

    @Test
    public void contextLoads() {
    }

}

MockMVC 구성

  • Servlet을 Mocking 한 것이 구동됨

  • Mockup이 된 Servlet에 무언가 Interaction 할려면 MockMVC라는 클라이언트를 구성해야됨

  • MockMVC를 만드는 방법이 여러가지가 있지만 아래와 같이 구성하는 것이 가장 쉽게 만드는 방법임

    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
    @AutoConfigureMockMvc
    public class SampleControllerTest {
    
      @Autowired
      MockMvc mockMvc;
    }

MOCK Test Code 작성

  • Auto Import 가 꼬이면 Preferences - Editor - Auto Import 에서 제거 하시면 됩니다
  • Print로 찍은 대부분의 내용을 다 확인해볼 수 있음

MOCK로 테스트 하는 방법

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc
public class SampleControllerTest {

    @Autowired
    MockMvc mockMvc;

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

RANDOM_PORT 구성

SpringBootTest.WebEnvironment.RANDOM_PORT로 설정하면 실제로 내장 Tomcat이 구동되고 Servlet이 올라감

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

TestRestTemplate

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleControllerRestTemplate {

    @Autowired
    TestRestTemplate testRestTemplate;

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

@MockBean

  • @SpringBootTest@SpringBootApplication을 찾아가서 모든 빈을 다등록하고
  • @MockBean으로 등록된 사항에 대해서 Mock 빈으로 교체하므로 테스트시 비용이 크고 통합테스트에 어울린다
  • @MockBean으로 교체된 Mock 빈은 @Test마다 Reset 되고 다시 적용되므로 Reset관리를 할필요가 없음

main Service로 테스트를 하면 테스트 코드가 너무 커지는 문제가 있어
@MockBean으로 main의 Service를 가로채서 가상의 Test Service를 만들어줌
정말 간편하게 테스트 할 수 있게 해줌

    @Autowired
    TestRestTemplate testRestTemplate;

    @MockBean
    SampleService mockSampleService;

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

WebTestClient

  • Spring5의 WebFlux에 추가된 RestClient 중 하나로 Asynchronous(비동기식) 방식
  • 기존에 RestClient는 Synchronous(동기식)
  • 사용하려면 webflux dependency를 추가해줘야함
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
Test Code 작성
    @Autowired
    WebTestClient webTestClient;

    @MockBean
    SampleService mockSampleService;

    @Test
    public void hello() throws Exception {
        when(mockSampleService.getName()).thenReturn("ironman");
        webTestClient.get().uri("/hello").exchange()
                .expectStatus().isOk()
                .expectBody(String.class).isEqualTo("hello ironman");
    }

슬라이스 테스트

레이어 별로 잘라서 테스트하고 싶을 때

@JsonTest

https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-autoconfigured-json-tests

예상되는 JSON 형식을 테스트 해볼 수 있음

import static org.assertj.core.api.Assertions.*;

@RunWith(SpringRunner.class)
@JsonTest
public class MyJsonTests {

    @Autowired
    private JacksonTester<VehicleDetails> json;

    @Test
    public void testSerialize() throws Exception {
        VehicleDetails details = new VehicleDetails("Honda", "Civic");
        // Assert against a `.json` file in the same package as the test
        assertThat(this.json.write(details)).isEqualToJson("expected.json");
        // Or use JSON path based assertions
        assertThat(this.json.write(details)).hasJsonPathStringValue("@.make");
        assertThat(this.json.write(details)).extractingJsonPathStringValue("@.make")
                .isEqualTo("Honda");
    }

    @Test
    public void testDeserialize() throws Exception {
        String content = "{\"make\":\"Ford\",\"model\":\"Focus\"}";
        assertThat(this.json.parse(content))
                .isEqualTo(new VehicleDetails("Ford", "Focus"));
        assertThat(this.json.parseObject(content).getMake()).isEqualTo("Ford");
    }

}

@WebMvcTest

https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests

  • 빈 하나만 테스트하므로 굉장히 가벼움
  • 딱 테스트 할 Controller와 필수 웹과 관련된 모듈들만 빈으로 등록되고 나머진 빈으로 등록되지 않음
  • @Controller, @ControllerAdvice, @JsonComponent, Converter, GenericConverter, Filter, WebMvcConfigurer, HandlerMethodArgumentResolver 만 빈 으로 등록됨
  • 사용할 빈이 있다면 @MockBean으로 만들어서 다 채워줘야 함 그래야 Controller이 필요한 빈을 주입받을 수 있다
  • @WebMvcTestMockMvc로 테스트 해야함

Test Code 작성

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

    @MockBean
    SampleService mockSampleService;

    @Autowired
    MockMvc mockMvc;

    @Test
    public void hello() throws Exception {
        when(mockSampleService.getName()).thenReturn("ironman"); // MockBean으로 주입한 Mock Service

        mockMvc.perform(get("/hello")) // get 으로 /hello 요청하면
                .andExpect(status().isOk()) // status 는 200 이고
                .andExpect(content().string("hello ironman")) // content 는 hello ironman 이고
                .andDo(print()); // 해당 사항들을 print로 출력함
    }
}
728x90

댓글

💲 추천 글