Goal : 스프링부트 환경에서 테스트 코드를 작성해본다.
단위테스트 란?
TDD의 첫 번째 단계인 기능 단위의 테스트 코드를 작성하는 것을 이야기한다. TDD와는 다른 이야기!
기존의 개발 진행 방식
- 코드 작성
- 프로그램(Tomcat) 실행
- Postman과 같은 api 테스트 도구로 http요청
- 요청 결과를 system.out.println()으로 눈으로 검증
- 결과가 다르면 다시 프로그램(Tomcat)을 중지하고 코드 수정
-> 테스트 코드가 없다보니 수정된 코드를 확인할 수 없어 2~5의 단계를 반복해야하는 문제
-> 톰캣 재시작은 많은 시간 소요
-> 눈으로 확인하는 수동 검증 필요
-> 기존에 잘 되던 기능의 문제 (사이드 이펙트)
백문이 불여일타. 코드로 개념을 이해해보자!
예제1. Hello Controller 테스트 코드 작성
1.1 메인클래스 생성
package com.jojoldu.book.springboot;
@SpringBootApplication
public class Application {
// @SpringBootApplication로 인해 스프링 부트의 자동 설정, 스프링 bean읽기와 생성 모두 자동 설정
// 특히 Application이 있는 위치부터 설정을 읽어가기 때문에, 이 클래스는 항상 프로젝트의 최상단에 위치해야함
public static void main(String[] args){
//main 메소드에서 실행하는 SpringApplication.run으로 인해 내장 was를 실행한다. -> 별도 톰캣 설치 x
SpringApplication.run(Application.class, args);
}
}
1.2 컨트롤러 생성 후 API 만들기
package com.jojoldu.book.springboot.web;
@RestController
public class HelloController {
/**
* @RestController
* 컨트롤러를 json을 반환하는 컨트롤러로 만들어줌
* 예전의 @ReponseBody를 각메소드마다 선언했던 것을 한번에 사용할수 있도록 만들어줌
*/
@GetMapping("/hello")
public String hello(){
return "hello";
}
}
1.3 test 패키지에 테스트 코드 작성
package com.jojoldu.book.springboot.web;
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = HelloController.class)
public class HelloControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void hello_return() throws Exception {
String hello = "hello";
mvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string(hello));
}
}
1.4 HelloControllerTest 실행
-> 우리가 검증용으로 선언했던 .andExpect(status().isOk())와 .andExpect(content().string(hello))가 모두 테스트를 통과했음을 의미한다.
※ 브라우저로 한 번씩 검증은 하되, 테스트 코드는 꼭 작성해야 한다. 절대 수동 검증하고 테스트 코드를 작성하지 않는다!
예제2. Hello Controller 코드를 롬북으로 전환하기
Lombok 이란?
자바로 개발시에 자주 사용하는 코드인 Getter, Setter, 기본생성자, toString등을 어노테이션으로 자동 생성해주는 라이브러리
2.1 dto 패키지 생성 후 HelloResponseDto 생성
package com.jojoldu.book.springboot.web.dto;
@Getter
@RequiredArgsConstructor
public class HelloResponseDto {
/**
* 1. @Getter 선언된 모든 필드의 get메소드를 생성
* 2. @RequiredArgsConstructor
* 선언된 모든 final 필드가 포함된 생성자를 생성
* final이 없는 필드는 생성자에 포함하지 않는다
*/
private final String name;
private final int amount;
}
2.2 Dto에 적용된 롬복이 잘 동작하는지 테스트 코드 작성해보기
package com.jojoldu.book.springboot.web.dto;
public class HelloResponseDtoTest {
@Test
public void lombok_test(){
//given
String name= "test";
int amount = 1000;
//when
HelloResponseDto dto = new HelloResponseDto(name, amount);
//then
assertThat(dto.getName()).isEqualTo(name);
assertThat(dto.getAmount()).isEqualTo(amount);
}
}
2.3 HelloResponseDtoTest 실행
-> 롬복의 @Getter로 get메소드가 @RequiredArgsConstructor로 생성자가 자동 생성됨이 증명 됨
2.4 HelloController에서 새로 만든 ResponseDto를 사용하도록 코드 추가
package com.jojoldu.book.springboot.web;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.hamcrest.core.Is.is;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Test
public void helloDto_return() throws Exception {
String name = "hello";
int amount = 1000;
mvc.perform(
get("/hello/dto")
.param("name", name)
.param("amount", String.valueOf(amount)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name", is(name)))
.andExpect(jsonPath("$.amount", is(amount))
);
}
2.5 helloDto_return() 실행
-> JSON이 리턴되는 API 정상적으로 테스트 통과 확인
※ 1.3의 코드 설명
- @RunWith(SpringRunner.class)
- 테스트를 진행할 때 JUnit에 내장된 실행자 외에 다른 실행자를 실행시킨다
- 여기서는 SpringRunner라는 스프링 실행자를 사용한다
- 즉, 스프링 부트 테스트와 JUnit 사이에 연결자 역할을 한다
- @WebMvcTest
- 여러 스프링 테스트 어노테이션 중, Web(Spring MVC)에 집중할 수 있는 어노테이션
- 선언할 경우 @Controller, @ControllerAdvice등을 사용할 수 있다
- 단 @Service, @Component, @Repository등은 사용할 수 없다
- 여기서는 컨트롤러만 사용하기 때문에 선언한다
- @Autowired
- 스프링이 관리하는 빈(Bean)을 주입받는다
- private MockMvc mvc
- 웹 API를 테스트 시에 사용
- 스프링 MVC 테스트의 시작점
- 이 클래스를 통해 HTTP GET, POST 등에 대한 API 테스트 가능
- mvc.perform(get("/hello"))
- MockMvc를 통해 /hello 주소로 HTTP GET 요청을 한다
- 체이닝이 지원되어 아래와 같이 여러 검증을 이어 선언할 수 있다.
- .andExpect(status().isOk())
- mvc.perform의 결과를 검증
- HTTP Header의 Status를 검증
- 우리가 흔히 알고 있는 200,404,500 등의 상태 검증
- 여기선 OK 즉, 200인지 아닌지 검증
- .andExpect(content().string(hello));
- mvc.perform의 결과 검증
- 응답 본문의 내용 검증
- Controller에서 "hello"를 리턴하기 때문에 이 값이 맞는지 검증
※ 2.2 코드 설명
- assertThat
- assertj라는 테스트 검증 라이브러리의 검증 메소드이다
- 검증하고 싶은 대상을 메소드 대상으로 받는다
- 메소드 체이닝이 지원되어 isEqualTo와 같이 메소드를 이어서 사용할 수 있다
- isEqualTo
- assertj의 동등 비교 메소드
- assertThat에 있는 isEqualTo의 값을 비교하여 같을 때만 성공이다
- Junit의 assertThat이 아닌 assertj의 assertThat을 사용
- Junit의 assertThat을 사용하면 is() 와 같이 CoreMatchers 라이브러리가 필요
- 자동완성이 확실하게 지원된다
※ 2.4 코드 설명
- param
- API 테스트할 때 사용될 요청 파라미터 설정
- 단, 값은 String만 허용
- 그래서 숫자/날짜 등의 데이터도 등록시에는 문자열로 변경해야 가능하다
- jsonPath
- JSON 응답값을 필드별로 검증할 수 있는 메소드
- $를 기준으로 필드명을 명시
- 여기서는 name과 amount를 검증하니 $.name, $amount로 검증
- import static org.hamcrest.core.Is.is; 를 사용한다
'책 > 스프링부트와 AWS로 혼자 구현하는 웹서비스' 카테고리의 다른 글
[스프링 부트와 AWS로 혼자 구현하는 웹 서비스 5장] - 스프링 시큐리티와 OAuth2.0으로 로그인 기능 구현하기 (0) | 2023.03.21 |
---|---|
[스프링 부트와 AWS로 혼자 구현하는 웹 서비스 4장] - 머스테치로 화면 구성하기 (0) | 2023.03.16 |
[스프링 부트와 AWS로 혼자 구현하는 웹 서비스 3장] - 스프링 부트에서 JPA로 데이터베이스 다뤄보자 (0) | 2023.03.15 |