5주 차 강의 내용 정리
- 단위 테스트
- 통합 테스트
단위 테스트
- 특정 단위(테스트 대상)가 의도한 대로 작동하는지 검증
단위란?
- 사람마다 정의가 다를 수 있음. 작은부분이라는 점에 초점을 맞추면 됨.
- 단일 메서드에서 전체 클래스까지 될 수 있음.
통합과 고립(Sociable and Solitary)
- 단위 테스트 작성 시 관계를 맺고 있는 대상(협력 객체)이 있는 경우를 고려해야 함.
- 협력 객체를 실제 객체로 사용할지, Mock 객체로 사용할지에 따라 테스트 구현이 달라짐.
단위의 정의를 논하기 앞서 테스트하는 단위가 통합(Sociable)되어야 하는지 고립(Solitary)되어야 하는지 고려해야 함.
Test Double
- 테스트 목적으로 실제 객체 대신 사용되는 모든 종류의 객체를 표현하는 일반 용어.
- 즉 실제(클래스, 모듈, 매서드)를 가짜 버전으로 대체한다는 의미.
Stubbing
- 테스트 동안 호출이 되면 미리 지정된 답변으로 응답.
- 미리 지정된 것 외의 것에 대해서는 응답 하지 않음.
Mockito, MockitoExtension, Spring 등을 활용한 Stubbing 방법이 있다.
MockitoExtension을 활용한 예시
@ExtendWith(MockitoExtension.class)
public class AuthServiceTest {
public static final String EMAIL = "email@email.com";
public static final String PASSWORD = "password";
public static final int AGE = 10;
private AuthService authService;
@Mock
private MemberRepository memberRepository;
@Mock
private JwtTokenProvider jwtTokenProvider;
@BeforeEach
void setUp() {
authService = new AuthService(memberRepository, jwtTokenProvider);
}
@Test
void login() {
when(memberRepository.findByEmail(anyString())).thenReturn(Optional.of(new Member(EMAIL, PASSWORD, AGE)));
when(jwtTokenProvider.createToken(anyString())).thenReturn("TOKEN");
TokenResponse token = authService.login(new TokenRequest(EMAIL, PASSWORD));
assertThat(token.getAccessToken()).isNotBlank();
}
}
Test Double은 언제 쓰는가?
- 테스트 대상이 협력 객체를 가질 때 사용한다.
실제 객체를 사용하면 협력 객체의 행위를 협력 객체 스스로가 정의
가짜 객체를 사용하면 협력 객체의 행위를 테스트가 정의
가짜 객체 특징
- 가짜 객체를 사용 할 경우 테스트 대상을 검증할 때 외부 요인(협력 객체)으로 부터 철저히 격리
- 하지만 테스트가 협력 객체의 상세 구현을 알아야 함
실제 객체 특징
- 실제 객체를 사용 할 경우 협력 객체의 상세 구현에 대해서 알 필요가 없음
- 하지만 협력 객체의 정상 동작 여부에 영향을 받음
테스트 코드를 작성 할 때
- 가짜 객체를 활용하면 실제 객체를 사용할 때 보다 조금 더 편하게 테스트를 작성할 수 있음
- 하지만 상세 구현에 의존하는 테스트가 될 수 있음
추천하는 방법
- 우선 TDD를 연습할 때 가급적이면 실제 객체를 활용하는 것을 우선으로 진행
- 테스트 작성이 어렵거나 흐름이 잘 이어지지 않는다면 테스트 더블을 활용하는 방법으로 접근하시는 것을 추천
통합 테스트
- 우리가 만드는 대부분의 애플리케이션은 데이터베이스, 파일 시스템, 외부 라이브러리 등과 같이 다른 애플리케이션과 통합되어 개발하는 경우가 많음
- 적은 비용과 빠른 테스트를 위해 단위 테스트를 주로 사용하지만 실제로 상호 작용하는 내용에 대한 검증도 반드시 필요함
- 예를 들면 데이터베이스와의 통합을 테스트하는 경우 테스트를 실행할 때 데이터베이스를 실행해야함
외부 라이브러리
테스트의 필요성
- 라이브러리 기능에 대한 검증은 필요 없음.
- 단, 그 부분을 사용하는 부분에 대한 검증이 필요.
변경할 수 없는 코드 검증 시 실제 객체 사용
- 작동 원리를 깊이 이해하기 어려움
- Mock 객체와 실제 객체의 행위를 일치시키기 어려움
@Test
void findPath() {
// graphService에서 활용하는 Jgrpah라이브러리의 객체를 실제 객체로 사용한다.
List<Long> stationIds = graphService.findPath(
Lists.list(line1, line2),
station3.getId(),
station5.getId(),
PathType.DISTANCE
);
assertThat(stationIds).hasSize(5);
assertThat(stationIds.get(0)).isEqualTo(3L);
assertThat(stationIds.get(1)).isEqualTo(2L);
assertThat(stationIds.get(2)).isEqualTo(1L);
assertThat(stationIds.get(3)).isEqualTo(4L);
assertThat(stationIds.get(4)).isEqualTo(5L);
}
데이터 베이스
- 테스트를 쉽게 하기 위해 메모리 내 H2 데이터베이스에 연결해서 한다.
@DataJdbcTest
public class StationRepositoryTest {
@Autowired
private StationRepository stationRepository;
@Test
void saveStation() {
String stationName = "강남역";
stationRepository.save(new Station(stationName));
assertThrows(DbActionExecutionException.class, () ->
stationRepository.save(new Station(stationName))
);
}
}
통합 테스트 vs 단위 테스트
- 통합 테스트는 통합하고 있는 부분을 실제와 가까운 환경에서 검증하여 기능이 정상적으로 여부를 검증
- 단위 테스트는 통합하고 있는 부분이 정상적으로 동작한다고 가정하고 단일 기능에 대해서만 검증
참고자료
'MyStory > dev_life' 카테고리의 다른 글
개발자 퍼스널 브랜딩 과정 후기 :Know yourself (0) | 2023.02.22 |
---|---|
동시성 이슈를 고려해서 쿠폰 발급하기 (Redisson을 활용한 분산 락 처리) (0) | 2023.02.19 |
우아한 테크 캠프 프로 4주차 회고 (0) | 2021.03.07 |
우아한 테크 캠프 PRO 3주차 회고 (0) | 2021.02.14 |
우아한 테크 캠프 PRO 2주차 회고 (0) | 2021.02.07 |