Home
All Posts
💯

테스트 코드는 왜 작성해야 하는가

Created
2023/11/09
Tags
TDD
Category
Project
2 more properties

나만의 이유 찾기

지난 2주 차 우테코 프리코스 공통 피드백에서는 "테스트를 작성하는 이유에 대해 본인의 경험을 토대로 정리해 본다"라는 문장과 함께 학습 자료를 제공받았다. JUnit을 학습하며 작은 단위의 유닛 테스트부터 만들고자 했다.
우테코 측에서 제공한 학습 테스트 중 일부

테스트 피라미드?

더불어, 단위 테스트라는 것에 대해 궁금해 서칭해 보다가 아래의 테스트 피라미드라는 개념을 알게 되었다. 이 개념에서 설명하길, Unit 테스트는 독립된 작은 조각으로 테스트하고, Integration 테스트는 여러 가지 방법으로 그룹으로 결합되어 테스트한다고 한다.
Test Pyramid @Amazon Alexa

단위 테스트란

이번 미션에서 요구하는 '단위 테스트'란 무엇인지 먼저 정의해 보자.
"단위 테스트란, 소프트웨어의 가장 작은 구성 요소, 가장 작은 코드 조각인 단위를 테스트하는 방법이다. 단위 테스트를 하는 목적은 각 장치가 제대로 작동하는지 확인하는 것이므로 다른 테스트와 독립적으로 동작을 테스트한다. 다시 말해, 테스트가 외부 시스템에 의존하는 경우 단위 테스트가 아닌 것이다. 궁극적으로는 단위들의 결함이 프로덕션 환경에 배포되는 것을 방지하기 위해 구현 전 설계 단계에서 작성되어야 한다는 것이다."
따라서 작은 단위의 함수나 모듈이 의도된 대로 정확히 작동하는지 테스트하고, 컨트롤러 테스트를 별도로 진행하지 않았다. 데이터베이스 연결 함수를 모킹화 하여도, 실제로 데이터베이스에 값을 넣는 것이 아니므로, 데이터베이스와의 연동에서도 제대로 테스트되는 것인지는 알 수 없기 때문이었다.
해당 함수에 테스트에 성공을 해도 실제 서비스의 실제 데이터베이스에서는 문제가 발생할 수 있다. 그럴 땐 유닛 테스트가 아닌, 통합 테스트나 시스템 테스트를 진행해야 할 것이다. (참고: [JEST] 모킹 Mocking 정리)

테스트 코드를 짜야하는 나만의 이유

개념을 공부하고, 테스트 코드와 함께 기능 구현을 하며 테스트를 작성하는 이유에 대해 아래와 같이 정리해 보았다.
일단 가장 좋은 이유는 "소스 코드에 대해 빠르게 피드백을 받을 수 있다는 것"이다. 사실 테스트 코드를 작성하지 않아도 되었던 1주 차 미션에서는 Integration 테스트만 하다 보니, 에러가 나면 어느 코드에서 누수가 되었는지 파악이 어려웠다. 반면, 테스트 코드를 작성한 2주 차와 3주 차에는 작은 단위의 메서드들부터 '이건 잘 됐어' '이건 잘못됐어'라는 피드백을 받으니 내 코드에 대한 신뢰도가 생겼다.
예를 들어, 공통 피드백에 "처음부터 큰 단위의 테스트를 만들지 않는다"라는 말이 있는 것처럼 이 미션에서 검증이 필요한 유틸 함수 두 개(양의 정수인지, 1000으로 나누어 떨어지는 숫자인지)를 만들었고, 이 소스코드를 테스트 코드를 통해 검증했다. 그리고 위 두 가지 메서드를 합쳐 구입 금액 클래스의 기능 테스트를 아래와 같이 네 파트로 나누어 진행했다.
import { ERROR } from '../../src/common/constants.js'; import MoneyValidator from '../../src/service/MoneyValidator.js'; describe('구매 금액 테스트', () => { const validateMoney = (input, expectedError) => { const moneyValidator = new MoneyValidator(input); if (expectedError) { expect(() => moneyValidator.validate()).toThrow(expectedError); } else { expect(() => moneyValidator.validate()).not.toThrow(); } }; test('금액이 유효한 형식이라면 성공', () => { validateMoney('10000'); }); test('금액이 1000 단위가 아니라면 실패', () => { validateMoney('1010', ERROR.money); }); test('금액이 문자열이라면 실패', () => { validateMoney('abc', ERROR.numeric); }); test('금액이 공백이라면 실패', () => { validateMoney(' ', ERROR.numeric); }); });
JavaScript
복사

관련 포스팅