[Section3] Spring MVC - Testing 2
2023. 7. 2. 16:25
🧑🏻💻 TIL(Today I Learned)
✔️ Hamcrest, Slice Test
💡 Hamcrest
➡️ JUnit 기반의 단위 테스트에서 사용할 수 있는 Assertion Framework
🔎 사용하는 이유?
- Assertion을 위한 매쳐(Matcher)가 자연스러운 문장으로 이어지므로 가독성이 향상됨
- 테스트 실패 메세지를 이해하기 쉬움
- 다양한 Matcher를 제공
➡️ 위와 같은 이유로 Assertion 메서드보다 더 많이 사용됨
🔎 Hamcrest Assertion 적용해 보기
✔️ JUnit에서의 Assertion
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class HelloJunitTest {
@DisplayName("Hello Junit Test")
@Test
public void assertionTest1() {
String actual = "Hello, JUnit";
String expected = "Hello, JUnit";
assertEquals(expected, actual); // 📍
}
}
✔️ Hamcrest에서의 Assertion
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
public class HelloHamcrestTest {
@DisplayName("Hello Junit Test using hamcrest")
@Test
public void assertionTest1() {
String expected = "Hello, JUnit";
String actual = "Hello, JUnit";
assertThat(actual, is(equalTo(expected))); // 📍
}
}
💡 Slice Test
➡️ 하나의 애플리케이션은 계층별로 역할이 있고 계층별로 서로 연동되기 때문에 각각의 계층 별로 잘 동작하는지 테스트를 진행한 후에 마지막으로 통합 테스트를 통해서 계층 간의 연동에 문제가 없는지 확인해야 함
➡️ 위처럼 개발자가 각 계층에 구현해 놓은 기능들이 잘 동작하는지 특정 계층만 잘라서 테스트하는 것
스모크 테스트(Smoke Test)
: QA 부서에서 본격적으로 전체적인 기능 테스트를 진행하기 전에 애플리케이션의 특정 수정 사항으로 인해 영향을 받을 수 있는 범위에 한해서 제한된 테스트를 진행하는 것
🔎 API 계층 테스트
➡️ 테스트 대상은 Controller, Spring에서는 Controller를 테스트하기 위한 편리한 방법을 제공함
➡️ 테스트 클래스의 기본 구조는 아래와 같음
@SpringBootTest
@AutoConfigureMockMvc
public class ControllerTestDefaultStructure {
@Autowired
private MockMvc mockMvc;
@Test
public void postMemberTest() {
//given --> 테스트용 request body 생성
//when --> MockMvc 객체로 테스트 대상 Controller 호출
//then --> Controller 핸들러 메서드에서 응답으로 수신한 HTTP Status 및 response body 검증
}
}
- @SpringBootTest
: SpringBoot 기반의 애플리케이션을 테스트하기 위한 Application Context 생성(필요한 Bean 객체들이 등록되어 있음) - @AutoConfigureMockMvc
: Controller 테스트를 위한 애플리케이션의 자동 구성 작업 해줌 - @Autowired 로 주입받은 MockMvc
: 톰캣과 같은 서버를 실행하지 않고 Spring 기반 애플리케이션의 Controller를 테스트할 수 있는 환경을 지원해 주는 일종의 Spring MVC 테스트 프레임워크
: MockMvc 통해서 작성한 Controller를 호출해서 쉽게 Controller에 대한 테스트를 진행할 수 있음
✔️ 실습
@SpringBootTest
@AutoConfigureMockMvc
public class MemberControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private Gson gson;
@Test
void postMemberTest() throws Exception {
//given --> 테스트용 requestbody 만들기
MemberDto.Post post = new MemberDto.Post("hgd@gmail.com", "홍길동", "010-1111-2222");
// Json 포맷으로 변환
String content = gson.toJson(post);
//when --> MockMvc 객체 통해 요청 URI와 HTTP 메서드 지정, 테스트용 requestbody 추가하여 request 수행
ResultActions actions = mockMvc.perform(
post("/v11/members")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(content)
);
//then --> responsebody 데이터를 통해 검증 작업 진행
// 위에서 리턴한 ResultActions 타입의 객체를 이용해서 request에 대한 검증 수행 가능
actions
.andExpect(status().isCreated())
.andExpect(header().string("Location", is(startsWith("/v11/members/"))));
// HTTP header에 추가된 Location의 문자열 값이 "/v11/members/" 로 시작하는지 검증
// Location header가 예상하는 값과 일치한다는 것은 백엔드 측에 회원 정보가 잘 생성되었다는 것을 의미함
}
- given : 테스트용 requestbody 만들기
- when : MockMvc 객체 통해 요청 URI와 HTTP 메서드 지정, 테스트용 requestbody 추가하여 request 수행
→ ResultActions
: Spring MVC 테스트 프레임워크에서 요청을 수행한 후 결과에 대한 추가 작업을 수행하기 위한 객체
: 요청에 대한 응답을 검증하고 기대값과 비교하는 등의 작업 수행할 수 있음
→ perform()
: MockMvc 객체를 사용하여 요청을 실행하고 응답에 대한 ResultActions 객체 반환
→ post()
: MockHttpRequestBuilders 가 MockHttpServletRequestBuilder 생성하기 위한 정적 팩토리 메서드 중 하나
(get(), patch(), delete() 등이 있음 )
→ accept(), contentType(), content()
: MockHttpServletRequestBuilder 메서드
: 각각 클라이언트에서 리턴 받을 응답 데이터 설정, 서버 쪽에서 처리 가능한 ContentType 설정, requestbody 데이터 설정 - then : responsebody 데이터를 통해 검증 작업 진행, 리턴한 ResultActions 타입의 객체 통해 request에 대한 검증 수행 가능
→ andExpect()
: 응답 결과를 검증할 수 있는 메서드, 리턴한 객체가 제공함
: andExpect()가 요구하는 ResultMatcher는 MockMvcResultMatchers에 정의된 정적 메서드 통해 생성 가능
: MockMvcResultMatchers 객체는 컨트롤러가 어떤 결과를 전송했는지 서버의 응답 결과를 검증함
🔎 데이터 액세스 계층 테스트
➡️ 데이터 액세스 계층 테스트 시에는 아래의 한 가지 규칙을 꼭 지켜야 함
⭐️ DB의 상태를 테스트 케이스 실행 이전으로 되돌려서 깨끗하게 만든다.
public class DataAccessLayerTest {
@Test
public void testA() {
// (1-1) 데이터가 DB에 잘 저장되는지를 테스트하기 위해 한 건의 데이터를 DB에 저장
// (1-2) DB에 잘 저장되었는지 DB에서 조회해서 결과를 확인
}
@Test
public void testB() {
// (2-1) 데이터가 DB에서 잘 조회 되는지를 테스트하기 위해 DB에서 조회
}
}
- JUnit으로 작성한 테스트 케이스는 항상 일정한 순서로 테스트 케이스가 실행된다는 보장이 없음
- A -> B 순서대로 실행되면 "passed" 지만 다시 테스트 케이스를 시작했을 때 만약 test B() 가 먼저 실행된다면 결과는 "failed"
=> testA() 가 먼저 실행이 되지 않아 저장된 데이터가 없기 때문에 - 위처럼 테스트 케이스는 여러 개의 테스트 케이스를 일괄적으로 실행시키더라도 각각의 테스트 케이스에 독립성이 보장되어야 함
- 문제가 발생하지 않도록 하는 가장 좋은 방법은 테스트 케이스 하나가 실행될 때 해당 테스트 케이스에서 사용했던 데이터가 DB에 저장이 되어 있는 상태라면 테스트 케이스 실행 종료 시점에 저장되었던 데이터를 삭제해 주는 것
'SEB_BE_45 > 공부 정리' 카테고리의 다른 글
[Section3] Spring MVC - API 문서화 (0) | 2023.07.03 |
---|---|
[Section3] Spring MVC - Testing 3 (0) | 2023.07.02 |
[Section3] Spring MVC - 테스팅(Testing) (0) | 2023.06.28 |
[Section3] Spring MVC - 트랜잭션(Transaction) (0) | 2023.06.26 |
[Section3] Spring MVC - JPA 기반 액세스 계층 (0) | 2023.06.21 |