한 문단에 한 주제
- if, for 등 논리 구조가 들어갈 경우 여러 주제가 포함될 확률이 높고, test를 읽는 사람이 자연스럽게 읽기 힘듦
(생각을 하면서 읽어야 됨)- 테스트가 @DisplayName에서 한 문장으로 설명될 수 있는가?
완벽하게 제어하기
- 제어할 수 없는 변수(ex, LocalDateTime.now()) 는 상위 클래스에서 주입받는걸로 변경
- 외부 시스템에 대해 Mocking 처리를 하고 테스트 구성을 하자
테스트 환경의 독립성 보장
- 테스트가 깨져도 when, then 절에서 깨져야 하는데, 테스트 구성을 하는 given 절에서 실패하면 논리적으로 맞지 않음
각 테스트 사이의 독립성 보장
- 언제 수행되었든 항상 같은 결과 보장
- 테스트 수행 환경을 항상 동일하게
- 공유자원 사용 배제
한 눈에 들어오는 Text Fixture
Text Fixture -> 테스트를 위해 원하는 상태로 고정시킨 객체
- setUp 같은 함수 사용하면 모든 Test에 영향을 미침
- BeforeEach 등 함수는 각 테스트 입장에서 해당 메서드 내부를 모르고, 수정해도 아무 변화가 없다면 사용 가능
Text Fixture 클렌징
- deleteAll과 deleteAllInBatch의 차이
-> deleteAll은 전체를 Select해서 건 당 delete로 지워줘서 쿼리가 길어짐
-> 다만 매핑된 다른 테이블도 다 건 당 delete로 지줌
-> deleteAll과 deleteAllInBatch의 성능 차이가 발생- 지울때도 순서 따라서 잘 지워야 함 -> 외래키 제약 조건 방지
ParamiterizedTest
- @ParamiterizedTest를 통해 여러 case에 대해 test를 한 번에 수행
예시코드
@DisplayName("상품 타입이 재고 타입인지 체크한다.")
@CsvSource({"HANDMADE,false", "BOTTLE,true", "BAKERY,true"})
@ParameterizedTest
void containsStockType3(ProductType productType, boolean expected){
//given
//when
boolean result = ProductType.containsStockType(productType);
//then
assertThat(result).isEqualTo(expected);
}
- @TestFactory를 사용하고, 아래에서 여러 행동을 결합하여 특정 시나리오대로 테스트 진행
예시코드
@DisplayName("재고 차감 시나리오")
@TestFactory
Collection<DynamicTest> stockDeductionDynamicTest(){
//given
Stock stock = Stock.create("001", 1);
return List.of(
DynamicTest.dynamicTest("재고를 주어진 개수만큼 차감할 수 있다.", () -> {
//given
int quantity = 1;
//when
stock.deductQuantity(quantity);
//then
assertThat(stock.getQuantity()).isZero();
}),
DynamicTest.dynamicTest("재고보다 많은 수의 수량으로 차감 시도하는 경우 예외가 발생한다.", () -> {
//given
int quantity = 1;
//when //then
assertThatThrownBy(() -> stock.deductQuantity(quantity))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("차감할 재고 수량이 없습니다.");
})
);
}
테스트 환경 통일
- ActiveProfile 차이 등으로 인해 테스트시 SpringBoot 서버가 새로 뜸. 이는 자원 낭비
- 환경을 통합하는 부모 클래스를 만들고, 이를 상속하게 하면서 이러한 테스트 시 서버 재가동 줄일 수 있음
- Mock의 경우에는 또 다른 환경이므로 이에 대핸 구분 필요 (Mock을 사용하는 class끼리만 통합)
- Presentation 계층의 경우 @SpringBootTest가 아닌 @WebMvcTest 사용하므로 통합 어려움, 같은 계층끼리만 통합
private 메서드의 테스트
- 할 필요 없음
- 외부(호출하는 입장)에서는 private method는 알 필요가 없음
- private method를 사용하는 쪽에서 test를 진행하면 자연럽게 해당 private method의 검증도 되는 구조
- 계속 이러한 필요가 생각난다면, 오히려 클래스의 책임 분리에 대해 생각할 떄 일지도..
production에서는 필요 없고 test에만 필요한 코드라면?
- 만들어도 되지만 보수적으로 접근
- 정말 꼭 필요한 경우에만 작성하자