요즘 CICD 공부에 푹 빠져, AWS와 Docker등과 굉장히 친하게 지내고 있었다
그러다보니 CD는 구현이 가능한데,
정작 CI에 대한 이해가 한참 부족한 나를 발견하였다
이전에 TDD의 중요성을 김영한 교육자님의 강의에서 얼핏 들은 기억이 있지만
단위테스트의 중요성을 아예 체감하지 못하고 있었다
왜냐면 내가 만드는 서비스의 경우 로컬에서 서버를 가동시켜, 스웨거를 통한 통합테스트까지 걸리는 시간이 그닥 오래 걸리지 않았기 때문이다
하지만 내가 추후 규모있는 프로젝트를 진행하게 된다면, 더이상 이러한 식의 통합테스트로는 프로젝트를 구동하기 힘들어진다
또한 CI 과정에서 해당 코드의 형상관리를 하는데에도 TDD가 중점적으로 작동하기 때문에, 이번 구름톤 프로젝트를 기점으로 TDD를 공부하여 적용해보려고 한다
https://mangkyu.tistory.com
정리가 너무 잘 되어있는 자료를 발견하여 출처를 남깁니다
단위테스트는 하나의 모듈을 기준으로 독립적으로 진행되는 가장 작은 단위의 테스트이다
이를 와닿게 설명하자면 애플리케이션에서 작동하는 하나의 기능 또는 메소드를 기준으로 테스트를 작성하는 방법을 의미한다
이러한 테스트의 결과는 "하나의 메서드가 정상적으로 작동하는가" 만 검증하는 방법이다
통합테스트는 여러개의 모듈을 통합하는 과정에서 모듈간의 호환성을 검사하기 위해 하는 테스트로서, 독립적인 기능을 테스트하는 것이 아닌 API 호출 시점부터 데이터 관리까지의 전체적인 부분을 테스트하는 것을 의미한다
프로젝트가 어느정도 구성이 완료되고 나면, 하나의 프로젝트를 구성하기 위해서 데이터베이스와 캐시, 외부API를 비롯한 다양한 모듈들이 함께 구동이 되어야한다
잦게 진행되는 테스트를 위해서 매번 이렇게 많은 모듈이 작동하는건 크게 비효율적이므로 우리는 작은 모듈단위의 테스트 진행을 구현할 필요가 있다
또한 코드가 리팩터링 되었을때, 미리 작성해놓은 테스트코드가 있다면 해당 코드만 돌려보아도 모듈별 테스트가 가능해지기 때문에 리팩터링에도 큰 장점을 갖는다
계속해서 이야기 하였듯이 테스트를 하는데에는 아무리 모듈단위로 진행한다고 하여도 다른 모듈이 필요 할 수 밖에 없다
우리는 그럴때 실제 객체 대신 가짜객체 (Mock Object)를 주입하여 사용한다. 그리고 그런 가짜 객체에 데이터를 주입하고 반응값을 결정하는 것을 Stub이라고 한다. Junit5 자체에서 stub을 지원하지는 않고, Mockito와 같은 모킹 라이브러리를 이용해서 stub를 구현하게 된다
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ServiceTest {
@Test
void testWithStub() {
// 종속성을 가진 Repository의 스텁 생성
Repository repositoryStub = Mockito.mock(Repository.class);
Mockito.when(repositoryStub.getData()).thenReturn("stubbed data");
// 스텁을 사용해 Service 객체 생성
Service service = new Service(repositoryStub);
// 테스트 수행
String result = service.getProcessedData();
assertEquals("processed: stubbed data", result);
}
}
간단학 작성해본 Mockito코드
이런식으로 stub이 구현된다
단위테스트는 코드가 변하더라도 같은 테스트 코드를 이용하여 계속해서 그 코드로 모듈을 검증 할 수 있어야한다.
코드의 구성이 변화하는거지 기본적인 기능 자체가 변화하는 일은 잘 없기 때문이다
그렇게 구성하기 위해서 우리는
이 두가지를 지켜야한다
또한 좋고 깨끗한 테스트 코드는 FIRST라는 5가지 규칙을 따라야 한다.
Fast: 테스트는 빠르게 동작하여 자주 돌릴 수 있어야 한다.
Independent: 각각의 테스트는 독립적이며 서로 의존해서는 안된다.
Repeatable: 어느 환경에서도 반복 가능해야 한다.
Self-Validating: 테스트는 성공 또는 실패로 bool 값으로 결과를 내어 자체적으로 검증되어야 한다.
Timely: 테스트는 적시에 즉, 테스트하려는 실제 코드를 구현하기 직전에 구현해야 한다.