티스토리 뷰
반응형
Spring Boot API TDD Start
현재 회사에서는 테스트 코드 문화가 없다 보니 간접적인 경험을 많이 해보고자 관련 영상들을 많이 찾아보고 있다.
최근 YOUTHCON'21 을 보고 손주원님이 발표하신 Spring Boot TDD 발표가 너무 인상 깊었고 많은 도움이 되어 정말 간략하게 내용을 정리해 보았다.
미래의 나 혹은 또 다른 누군가가 이 글을 보고 도움이 되길..
인수 테스트
인수 테스트
(Acceptance Test)
- 사용자의 시나리오(요구사항)를 기반으로 수행하는 테스트
- 소프트웨어가 사용자 요구사항을 충족하는지에 대한 테스트가 진행
인수 조건
(Acceptance Creteria)
- 사용자의 요구사항
@SpringBootTest
- 통합 테스트를 위한 @annotation
- 여러 모듈들이 의도한 대로 협력하는지를 테스트
- 개발자가 변경할 수 없는 외부 라이브러리까지 묶어서 검증
- 인수 테스트에서는 최대한 많은 자원을 활용하는 것이 좋아 통합 테스트를 진행
WebEnvironment
- 테스트 환경에 웹 환경을 설정하는 속성
- 기본값은 SpringBootTest.WebEnvironment.MOCK
- 실제 서블릿 컨테이너를 띄우지 않고 서블릿 컨테이너를 mocking(모의 객체 주입) 한 것이 실행
- embedded tomcat 을 띄워서 실제 운영 환경과 동일한 환경 구축
WebEnvironment.RANDOM_PORT
- 테스트 환경에서 PORT 가 충돌하지 않도록 지원
@LocalServerPort
- RANDOM_PORT 사용 시 @LocalServerPort 를 통해 port 확인
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class AcceptanceTest {
@LocalServerPort
int port;
@BeforeEach
void setUp() {
RestAssured.port = port;
}
@Test
void 성공() {
given()
.accept(MediaType.APPLICATION_JSON_VALUE)
.when()
.get("/reviews/1")
.then()
.statusCode(HttpStatus.OK.value())
.assertThat()
.body("id", equalTo(1))
.body("content", equalTo("좋았아요"))
.body("phoneNumber", equalTo("010-1234-1234"));
}
@Test
void 실패() {
given()
.accept(MediaType.APPLICATION_JSON_VALUE)
.when()
.get("/reviews/1000")
.then()
.statusCode(HttpStatus.NOT_FOUND.value());
}
}
Controller
@SpringBootTest
,@AutoConfigureMockMvc
를 사용하여 테스트할 수도 있지만 테스트 환경이 너무 무거워지는 단점이 발생- 단위테스트로 진행할 경우 @WebMvcTest 활용
@WebMvcTest
- Controller 에 있는 Bean 들만 로드
- 특정 컨트롤러 지정 가능
@MockBean
- 특정 Bean 을 모의 객체로 주입받아 사용
@WebMvcTest(ReviewController.class)
public class ReviewControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private ReviewService reviewService;
private Long id = 1L;
private String content = "좋았어요";
private String phoneNumber = "010-1234-1234";
@Test
void 성공() throws Exception {
//given
given(reviewService.getById(id))
.willReturn(new Review(id, content, phoneNumber));
//when
ResultActions perform = mockMvc.perform(get("/reviews/" + id));
//then
perform
.andExpect(status().isOk())
.andExpect(jsonPath("id").value(id))
.andExpect(jsonPath("content").value(content))
.andExpect(jsonPath("phoneNumber").value(phoneNumber));
}
@Test
void 실패() throws Exception {
//given
given(reviewService.getById(1000L))
.willThrow(new ReviewNotFoundException("no review id : " + 1000));
//when
ResultActions perform = mockMvc.perform(get("/reviews/" + 1000));
//then
perform
.andExpect(status().isNotFound());
}
}
Service
- mocking 을 사용하여 데이터베이스에 직접 접근하지 않고 비즈니스 영역에만 집중
- Service 에서는 Spring 통합 테스트가 아닌 단위 테스트로 진행하는 것이 좋음
class ReviewServiceTest {
private ReviewRepository reviewRepository = mock(ReviewRepository.class);
private ReviewService reviewService = new ReviewService(reviewRepository);
private Long id = 1L;
private String content = "좋았어요";
private String phoneNumber = "010-1234-1234";
@Test
void 성공() {
//given
given(reviewRepository.findById(id))
.willReturn(Optional.of(new Review(id, content, phoneNumber, false)));
//when
Review review = reviewService.getById(id);
//then
assertThat(review.getId()).isEqualTo(id);
assertThat(review.getContent()).isEqualTo(content);
assertThat(review.getPhoneNumber()).isEqualTo(phoneNumber);
}
@Test
void 실패() {
//given
given(reviewRepository.findById(1000L)).willReturn(Optional.empty());
assertThatThrownBy(() ->
//when
reviewService.getById(1000L))
//then
.isInstanceOf(ReviewNotFoundException.class);
}
}
Repository
@DataJpaTest
- JPA 관련 테스트 설정만 로드
@DataJpaTest
class ReviewRepositoryTest {
@Autowired
private ReviewRepository reviewRepository;
@Test
void 성공() {
//given when
Review review = reviewRepository.findById(1L)
.orElseThrow(RuntimeException::new);
//then
assertThat(review.getId()).isEqualTo(1L);
assertThat(review.getContent()).isEqualTo("재밌어요");
assertThat(review.getPhoneNumber()).isEqualTo("010-1111-2222");
}
@Test
void 실패(){
assertThatThrownBy(() ->
// given when
reviewRepository.findById(1000L)
.orElseThrow(() -> new ReviewNotFoundException("no review id :" + 1000L)))
// then
.isInstanceOf(ReviewNotFoundException.class);
}
}
Reference
YOUTHCON'21 손주원님의 Spring Boot TDD Start
반응형
'Web > Spring' 카테고리의 다른 글
Spring Boot 2.4 Config file processing (0) | 2022.02.11 |
---|---|
SpringBoot & Mybatis & MS-SQL (0) | 2022.01.31 |
[Spring Boot] Scheduler 사용해보기(일정 주기로 실행하는 스프링 스케쥴러) (2) | 2021.11.18 |
[Spring Boot] MongoDB + Pagination을 활용한 리스트 검색 기능 (0) | 2021.08.07 |
[Spring] 페이징 무한 스크롤 (Infinite Scrolling Pagination) (0) | 2021.07.11 |
댓글