단위 테스트(Unit Test)
단위 테스트(Unit Test)는 하나의 모듈을 기준으로 독립적으로 진행되는 가장 작은 단위의 테스트
여기서 모듈은 애플리케이션에서 작동하는 하나의 기능 또는 메소드
즉,"어떤 기능이 실행되면 어떤 결과가 나온다"를 테스트함
단위 테스트는 해당 부분만 독립적으로 테스트하기 때문에 어떤 코드를 리팩토링하여도 빠르게 문제 여부를 확인가능
실무에서는 단위 테스트를 선호하며, 요즘 많이 사용되는 TDD(Test-Driven Development, 테스트 주도 개발) 에서 얘기하는 테스트도 단위 테스트를 의미한다. 우리는 우리가 작성한 테스트 코드를 수시로 빠르게 돌리면서 문제를 파악할 수 있다.
통합 테스트(Integration Test)
통합 테스트(Integration Test)는 모듈을 통합하는 과정에서 모듈 간의 호환성을 확인하기 위해 수행되는 테스트
일반적으로 애플리케이션은 여러 개의 모듈들로 구성이 되고, 모듈들끼리 메세지를 주고 받으면서(함수 호출) 기능을 수행한다. 그렇기에 통합된 모듈들이 올바르게 연계되어 동작하는지 검증이 필요한데, 이러한 목적으로 진행되는 테스트가 통합 테스트이다. 그렇기에 통합 테스트는 독립적인 기능에 대한 테스트가 아니라 웹 페이지로부터 API를 호출하여 올바르게 동작하는 지를 확인하는 것
통합 테스트는 실제 여러 컴포넌트들 간의 상호작용을 테스트하기 때문에 모든 컴포넌트들이 구동된 상태에서 테스트를 하게 된다. 그렇기에 통합 테스트를 위해서는 캐시나 데이터베이스 등 다른 컴포넌트들과 실제 연결을 해야 하고, 시스템을 구성하는 컴포넌트들이 많아질수록 테스트를 위한 비용(시간)이 상당히 커진다.
요즘 Java 단위테스트 작성에는 크게 2가지 라이브러리가 사용된다.
- JUnit5: 자바 단위 테스트를 위한 테스팅 프레임워크
- AssertJ: 자바 테스트를 돕기 위해 다양한 문법을 지원하는 라이브러리
JUnit 만으로도 단위 테스트를 충분히 작성할 수 있다. 하지만 JUnit에서 제공하는 assertEquals()와 같은 메소드는 AssertJ가 주는 메소드에 비해 가독성이 떨어진다. 그렇기 때문에 순수 Java 애플리케이션에서 단위 테스트를 위해 JUnit5와 AssertJ 조합이 많이 사용된다.
클래스 상단에 mock을 사용하기 위한 어노테이션 추가
@ExtendWith(MockitoExtension.class)
[ given/when/then 패턴 ]
요즘 단위테스트는 거의 given-when-then 패턴으로 작성하는 추세이다.
given-when-then 패턴이란 1개의 단위 테스트를 3가지 단계로 나누어 처리하는 패턴으로, 각각의 단계는 다음을 의미한다.
- given(준비): 어떠한 데이터가 준비되었을 때
- when(실행): 어떠한 함수를 실행하면
- then(검증): 어떠한 결과가 나와야 한다.
@Test
@DisplayName("테스트 이름")
void serviceTest() {
// given
// when
// then
}
@DisplayName("로또 번호 갯수 테스트")
@Test
void lottoNumberSizeTest() {
// given
final LottoNumberGenerator lottoNumberGenerator = new LottoNumberGenerator();
final int price = 1000;
// when
final List<Integer> lottoNumber = lottoNumberGenerator.generate(price);
// then
assertThat(lotto.size()).isEqualTo(6);
}
assertThat assertFalse assertEquals
테스트 코드를 작성할 때 System.out.println()로 매번 출력해야하는 어려움을 줄이기 위해 assertThat()을 종종 사
assertFalse() 메서드는 주어진 조건이 거짓인지 확인하고, assertTrue() 메서드는 주어진 조건이 참
assertThat(lotto.size()).isEqualTo(6);
assertThat(result).isEqualTo(member1);
assertThat(lotto.stream().allMatch(v -> v >= 1 && v <= 45)).isTrue();
isEqualTo(e)
assertThat(lotto.size()).isEqualTo(6);
assertThat(result).isEqualTo(member1);
contains(e)
// Success: 모든 원소를 입력하지 않아도 성공
assertThat(list).contains(1, 2);
// Success: 중복된 값이 있어도 포함만 되어 있으면 성공
assertThat(list).contains(1, 2, 2);
// Success: 순서가 바뀌어도 값만 맞으면 성공
assertThat(list).contains(3, 2);
// Fail: List 에 없는 값을 입력하면 실패
assertThat(list).contains(1, 2, 3, 4);
doesNotContain(e)
assertFalse(str, doesNotContain(substring));
verify
특정 메소드가 알맞게 실행되었는지 유효성 검사를 한다
verify(userRepository, times(1)).findByIdAndDeleteTimeIsNull(anyInt());
verify(courseRepository, times(1)).findByIdAndDeleteTimeIsNull(anyInt());
verify(commentRepository, times(1)).save(any(Comment.class));
verify(commentImageRepository, times(2)).save(any());
Mockito
단위 테스트 시, 의존성을 가진 객체의 동작을 가짜 객체로 대체하여 테스트를 수행하는 데 사용
이를 통해 테스트 수행 시간을 단축하고, 의존성을 가진 객체의 동작을 모의(mocks)하여 테스트하는 데 이점을 제공
@InjectMocks
CourseServiceImpl courseService;
@Mock
CourseRepository courseRepository;
보통 Service 클래스는 Repository 클래스의 의존하게 된다.
따라서, Service를 단위테스트 하려면 Repository의 동작을 가짜 객체로 대체 해야되기 때문에 위 처럼 사용
'Backend > Java' 카테고리의 다른 글
객체 지향 프로그래밍 (1) | 2024.01.03 |
---|---|
[JAVA] Origin 서버가 대상 리소스를 위한 현재의 representation을 찾지 못했거나, 그것이 존재하는지를 밝히려 하지 않습니다. (1) | 2022.09.21 |
Cookie & Session (0) | 2022.09.20 |
JSP Programming (0) | 2022.09.16 |
Servlet Programming (0) | 2022.09.16 |