seaking110 님의 블로그
테스트 코드 remind 본문
테스트 코드
- unit 테스트 (단위 테스트) : 도메인 모델과 비즈니스 로직을 테스트, 작은 단위의 코드 및 알고리즘 테스트
- intergration 테스트 (통합 테스트) : 코드의 주요 흐름들을 통합적으로 테스트
- e2e 테스트 : 최종 사용자의 흐름에 대한 테스트이며 외부로부터의 요청부터 응답까지 기능이 잘 동작하는지에 대한 테스트
TDD (테스트 주도 개발)
- 테스트를 먼저 작성한 후 이를 만족하는 코드를 작성하고 리팩토링 하는 방식
- 진행 과정
- 원하는 기능을 먼저 테스트 코드로 작성 (무조건 실패)
- 해당 테스트를 통과하도록 실제 코드를 작성
- 코드 정리 후 다시 테스트를 실행하여 성공 여부 확인
- TDD의 한계
- TDD를 적용한다고 버그가 사라지는 것은 아님
- 개발 속도를 저하시킬 수 있기 때문에 상황에 따라 적절히 활용
좋은 테스트의 F.I.R.S.T 원칙
- FAST : 단위 테스트는 빠르게 수행
- Independent (독립적) : 각 테스트는 서로 간섭 없이 독립적으로 실행되어야 한다.
- Repeatable (반복 가능) : 동일한 입력으로 항상 같은 결과 보장
- Self-validating (자동 검증) : 테스트는 자동으로 성공/실패를 판별
- Timely (적시성) : 단위테스트는 실제 코드보다 먼저 작성하는 것이 이상적(TDD의 경우)
Given-When-Then
- given - when - then만 잘 지켜도 훌륭한 테스트 코드
JUnit + Mockito
- junit : 자바에서 가장 많이 사용하는 테스트 프레임워크
- Mockito : 가짜 객체를 사용하여 의존성을 줄이고 특정 상황을 시뮬레이션 할 수 있는 프레임 워크
- @Mock : Mock 객체 생성
- @Spy : 원본 객체를 유지하면서 일부만
효과적인 단위 테스트 작성법
- 유지 보수하기 쉬운 테스트
- 좋은 테스트의 특징
- 관련 없는 코드 변경으로 인한 실패 x
- 좋지 않은 테스트의 특징
- 검증 대상과 관련 없는 변경 때문에 실패하는 테스트
- 불명확한 테스트 : 뭐가 잘못되어 실패했는지 보완 사항을 알지 어려운 테스트
- 테스트 유지보수성 향상 방법
- 내부 구현이 아니라 결과를 검증하는 방식으로 작성
- 행위 중심 테스트를 지향
- 명확한 테스트 명명법 사용
- 테스트 코드에서 복잡한 논리는 지양
- Dly 원칙 보다 DAMP 원칙이 훨씬 더 중요
- 이해하기 쉬운 테스트 코드가 훨씬 더 중요하다!
안좋은 테스트 코드 예방하기
- 한 번 작성한 후로 대상 시스템의 요구사항이 바뀌지 않는 한 절대 수정할 일이 없어야 함
- 순수 리팩터링(외부 인터페이스는 놔두고 내부만 리팩터링 하는 경우) -> 테스트는 변경되지 않아야함
- 새로운 기능 추가 -> 테스트는 변경되지 않아야함 & 새로운 테스트 추가
- 버그 수정 -> 기존 테스트 변경 X & 누락된 테스트 추가
- 행위 추가 -> 기존 테스트 변경 O
- 과정이 아닌 결과에 초점을 맞춤
통합 테스트 개념
- 탄위 테스트만으로는 시스템이 전체적으로 동작하는지 확인 x
- 데이터베이스, 캐시(Redis), API 연동 등 외부 시스템과의 통합을 검증하는 테스트가 필요
- Postman을 이용한 API 테스트와 유사
User,UserRepository,UserService,UserController가 있다고 가정
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@Transactional
public class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private UserRepository userRepository;
@Test
public void shouldCreateUserAndRetrieveIt() throws Exception {
// Given - 사용자 데이터
String userJson = "{\"name\":\"John Doe\", \"email\":\"john@example.com\"}";
// When - POST 요청으로 사용자 생성
mockMvc.perform(post("/users")
.contentType(MediaType.APPLICATION_JSON)
.content(userJson))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("John Doe"))
.andExpect(jsonPath("$.email").value("john@example.com"));
// Then - GET 요청으로 방금 생성한 사용자 조회
mockMvc.perform(get("/users/john@example.com"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("John Doe"))
.andExpect(jsonPath("$.email").value("john@example.com"));
}
@Test
public void shouldReturn404ForNonExistentUser() throws Exception {
// When - 존재하지 않는 이메일 조회
mockMvc.perform(get("/users/nonexistent@example.com"))
.andExpect(status().isNotFound());
}
}
실행 결과
-성공
[ 2025-03-09 12:34:56 ] INFO
UserControllerIntegrationTest: shouldCreateUserAndRetrieveIt() PASSED
[ 2025-03-09 12:34:57 ] INFO
UserControllerIntegrationTest: shouldReturn404ForNonExistentUser() PASSED
-실패
[ 2025-03-09 12:34:58 ] ERROR UserControllerIntegrationTest: shouldReturn404ForNonExistentUser() FAILED
Expected: HTTP 404
Actual: HTTP 200
- @SpringBootTest
- Spring Boot 애플리케이션 컨텍스트 전체를 로드하여 실제 환경과 유사하게 테스트할 수 있도록 함.
- webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT 설정 시, 내장 웹 서버를 랜덤 포트에서 실행하여 통합 테스트 수행.
- @Transactional
- 테스트 종료 후 데이터베이스를 자동 롤백하여 데이터가 남지 않도록 방지.
- MockMvc
- HTTP 요청을 모의(mock)하여 실제 서버 없이 컨트롤러를 테스트할 수 있도록 지원.
- mockMvc.perform(post(“/users”)...)을 사용하여 실제 HTTP 요청을 보내는 것처럼 동작.
- jsonPath("$.name").value("John Doe")
- JSON 응답에서 특정 필드 값을 검증.
- status().isOk() / status().isNotFound()
- HTTP 응답 상태 코드가 기대한 값과 일치하는지 확인.
가독성을 올리기 위한 전략 - 공유 데이터 셋팅
- 공유 데이터를 미리 세팅
- 장점
- 모든 테스트에서 기능을 확인하기 위해 세팅해줘야 하는 파라미터 값, 변수를 매번 호출 필요 x
- 이후 엔티티나 어떤 값이 변경되더라도 공유 데이터만 변경하면 됨
- public final static String TEST_EMAIL1 = "TEST@NAVER.com" 으로 미리 지정
- User user = TEST_USER!1 이런식으로 미리 지정한 공유 데이터를 활용하여 가독성 높은 테스트 코드 작성 가능
'Today I Learned' 카테고리의 다른 글
Spring Security (0) | 2025.03.12 |
---|---|
연관관계와 N+1 (0) | 2025.03.11 |
헷갈리는 개념 정리 (2) | 2025.03.05 |
트러블 슈팅 (0) | 2025.02.27 |
프로젝트에 부족한 부분을 찾아 리팩토링 (0) | 2025.02.27 |