Spring
[스프링 부트와 AWS로 혼자 구현하는 웹 서비스] 2. 테스트코드 작성하기
주니어주니
2023. 8. 1. 00:14
1. TDD와 단위 테스트
- TDD (Test-Driven Development) : 테스트 주도 개발
- 테스트 코드를 먼저 작성
- 단위 테스트
- 기능 단위의 테스트 코드 작성
- 개발 단계 초기에 문제 발견
- 테스트 프레임워크 : xUnit
- 개발환경(x)에 따라 Unit 테스트를 도와주는 도구 (JUnit, DBUnit 등)
2. 메인 클래스
package com.example.studyspringbootwebservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StudySpringbootWebserviceApplication {
public static void main(String[] args) {
SpringApplication.run(StudySpringbootWebserviceApplication.class, args);
}
}
- @SpringBootApplication
- 스프링 부트의 자동 설정, 스프링 Bean 읽기와 생성 자동 설정
- 이 어노테이션이 있는 위치부터 설정 읽음 -> 프로젝트의 최상단
- Application.run()
- 내장 WAS 실행
- 톰캣 필요 X
3. 컨트롤러
package com.example.studyspringbootwebservice.web;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
}
- @RestController
- @Controller + @ResponseBody
- JSON 반환
4. 테스트
package com.example.studyspringbootwebservice.web;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
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.*;
@ExtendWith(SpringExtension.class)
@WebMvcTest(controllers = HelloController.class)
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));
}
}
- @ExtendWith(SpringExtension.class)
- @RunWith(SpringRunner.class) (JUnit4) -> @ExtendWith(SpringExtension.class) (JUnit5)
- @Autowired, @MockBean에 해당하는 것들만 application context를 로딩
- @WebMvcTest(controllers = HelloController.class)
- 필요한 빈만 등록하여 테스트
- 웹과 관련된 빈만 주입 (@Controller)
- MVC 부분 슬라이스 테스트 (보통 컨트롤러 하나만 테스트 하고싶을 때 사용)
- @Service, @Component, @Repository 등은 사용 X
- @SpringBootTest 는?
- 내부에 있는 스프링 빈 모두 등록 -> 느리고 무거워짐
- 실제 운영 환경과 가장 유사하게 테스트
- 변경에 자유로움
- @ExtendWith가 포함되어 있음
- private MockMvc mvc
- 웹 API 테스트할 때 사용
- 이 클래스를 통해 HTTP GET, POST 등에 대한 API 테스트 수행
- mvc.perform(get("/hello")
- MockMvc를 통해 /hello 로 GET 요청
- MockMvc를 통해 /hello 로 GET 요청
- .andExpect(status().isOk())
- mvc.perform의 결과 검증
- HTTP Header의 status가 OK(200)인지 검증
- .andExpect(content().string(hello))
- mvc.perform의 결과 검증
- 응답 본문의 내용 검증
5. 롬복 적용
1) 롬복 Dto
package com.example.studyspringbootwebservice.web.dto;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public class HelloResponseDto {
private final String name;
private final int amount;
}
- @RequiredArgsConstructor
- @RequiredArgsConstructor + final -> 생성자 생성
- final 없는 필드는 생성자 X
2) 롬복 Dto 테스트
package com.example.studyspringbootwebservice.web.dto;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;
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);
assertThat(dto.getAmount()).isEqualTo(amount);
}
}
6. Dto 적용
1) 컨트롤러
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/hello/dto")
public HelloResponseDto helloDto(@RequestParam("name") String name,
@RequestParam("amount") int amount) {
return new HelloResponseDto(name, amount);
}
}
- @RequestParam
- 외부에서 API로 넘긴 파라미터 가져옴
- 외부에서 "name"이라는 이름으로 넘긴 파라미터를 메소드의 파라미터 name에 저장
2) Dto 적용 테스트
package com.example.studyspringbootwebservice.web;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
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.*;
@ExtendWith(SpringExtension.class)
@WebMvcTest(controllers = HelloController.class)
class HelloControllerTest {
@Autowired
private MockMvc mvc;
...
@Test
public void helloDto가_리턴된다() 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)));
}
}
- param
- API 테스트할 때 사용될 요청 파라미터 설정
- String만 허용 (숫자, 날짜 -> 문자열로 변환해야 함)
- jsonPath
- JSON 응답값을 필드별로 검증할 수 있는 메소드
- $를 기준으로 필드명 명시