Spring/스프링 부트와 AWS로 혼자 구현하는 웹 서비스
테스트 코드 작성
ysm7663
2021. 8. 25. 17:15
728x90
■ TDD란?
TDD (Test Driven Development) : 테스트 주도 개발
□ 특징
- 테스트가 주도하는 개발
- 테스트 코드를 먼저 작성

ㅁ Red : 항상 실패하는 테스트를 먼저 작성
ㅁ Green : 테스트가 통과하는 프로덕션 코드를 작성
ㅁ REFACTORY : 테스트가 통과하면 프로덕션 코드를 리팩토링
■ 단위 테스트를 해야하는 이유
- 개발단계 초기에 문제를 발견하게 도와준다 (빠른 피드백 가능)
- 개발자가 나중에 코드를 리팩토링하거나 라이브러리 업그레이드 등에서 기존 기능이 올바르게 작동하는지 확인 가능하다(회기 테스트)
- 기능에 대한 불확실성을 감소시킬 수 있다
- 시스템에 대한 실제 문서를 제공한다 (단위 테스트 자체가 문서로 사용할 수 있디)
■ TDD vs 단위 테스트
| TDD | 단위테스트 | |
| 순서 | 테스트 먼저 | 상관 없음 |
| 리펙토링 여부 | O | X |
| 중점 | 테스트 중점 | 기능 중점 |
■ 테스트 프레임워크
xUnit : 개발환경에 따라 Unit 테스틑 도와주는 도구
□ 종류
- JUnit - Java
- DBUnit - DB
- CppUnit - C++
- NUnit - .net
■ HelloController 테스트 클래스 생성
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@RunWith(SpringRunner.class) // 1
@WebMvcTest(controllers = HelloController.class) // 2
public class HelloControllerTest {
@Autowired // 3
private MockMvc mvc; // 4
@Test
public void hello가_리턴된다() throws Exception {
String hello = "hello";
mvc.perform(get("/hello")) // 5
.andExpect(status().isOk()) //6
.andExpect(content().string(hello)); // 7
}
}
- JUnit에 내장된 실행자 외의 다른 실행자를 실행 >> SpringRunner
- Web에 집중시키는 Annotation
- JPA 기능이 작동하지 않음
- @Controller, @ControllerAdvice 사용 가능
- @Service, @Component, @Repository 사용 불가능
- 스프링이 관리하는 Bean을 주입 받음
- 웹 API를 테스트 할 때 사용, 스프링 MVC 테스트의 시작점
- HTTP GET, POST 등에 대한 API 테스트를 할 수 있음
- MockMvc를 통해 /hello 주소로 HTTP GET 요청
- 체이닝이 지원되어 아래와 같이 여러 검증 기능을 이어서 선언할 수 있다
- mvc.perform의 결과를 검증, HTTP Header의 Status를 점증
- 200, 404, 500 등의 상태를 검증
- status.isOk() >> 200 인지 아닌지 검증
- mvc.perform의 결과를 검증, 응답 본문의 내용을 검증
■ HelloResponseDto 테스트 클래스 생성
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat; // 3
public class HelloResponseDtoTest {
@Test
public void 롬복_기능_테스트() {
// given
String name = "test";
int amount = 1000;
// when
HelloResponseDto dto = new HelloResponseDto(name, amount);
// then
assertThat(dto.getName()).isEqualTo(name); // 1
assertThat(dto.getAmount()).isEqualTo(amount); // 2
}
}
- assertThat
- assertj라는 테스트 검증 라이브러리의 검증 메소드
- 검증하고 싶은 대상을 메소드 인자로 받음
- 메소드 체이닝이 지원되어 isEqualTo와 같이 메소드를 이어서 사용할 수 있음
- isEqualTo
- assertj의 동등 비교 메소드
- assertThat에 있는 값과 isEqualTo의 값을 비교해서 같을 때만 성공
- Junit의 assertThat이 아닌 assertj 의 assertThat 사용 이유
- CoreMatchers와 달리 추가적으로 라이브러리가 필요하지 않음
- 자동완성이 좀 더 확실하게 지원됨
* Given - When - Then Pattern??
: 어느 정도 실력이 있는 개발자라면 굳이 사용하지 않아도 되지만, 주니어 개발자 혹은 테스트 코드를 처음 작성하는 개발자는 테스트 코드 작성 실력 향상에 도움이 될 수 있다.
[준비 - 실행 - 검증]
준비 : 테스트를 위해 준비하는 과정
- 테스트에 사용하는 변수, 입력 값 등을 정의
- Mock 객체를 정의
실행 : 실제로 테스트를 실행하는 과정
검증 : 테스트를 검증
- 예상한 값, 실제 실행을 통해 나온 값을 비교, 검증
■ API를 테스트 하는 HelloController 테스트 클래스 생성
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
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;
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = HelloController.class)
public class HelloControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void hello가_리턴된다() throws Exception {
String hello = "hello";
mvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string(hello));
}
@Test
public void helloDto가_리턴된다() throws Exception {
String name = "hello";
int amount = 1000;
mvc.perform(
get("/hello/dto")
.param("name", name) // 1
.param("amount", String.valueOf(amount)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name", is(name))) // 2
.andExpect(jsonPath("$.amount", is(amount)));
}
}
* JSON이 리턴되는 API 역시 정상적으로 테스트가 통과하는 것을 확인 할 수 있다.
- API를 사용할 때 사용될 요청 파라미터를 설정 (값은 String만 허용, 숫자 등은 문자열로 변경해서 사용)
- JSON 응답값을 필드별로 검증할 수 있는 메소드
- $를 기준으로 필드명을 명시
* API(Application Programming Interface)란?
: 응용 프로그래밍에서 사용할 수 있도록 운영체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스
728x90