TDD는 '테스트 주도 개발'이라는 의미를 가진다. TDD는 소프트웨어 개발 방법론 중 하나로, 실제 코드를 작성하기 전에 테스트 코드를 먼저 작성하는 접근 방식을 말한다.
✍️ 이러한 테스트 유형들은 서로 다른 목적과 범위를 가지며, 테스트 전략에 따라 적절한 시점과 방법으로 조합되어 사용된다고 한다. 🤔
(1) 실패하는 테스트 작성
아직 구현되지 않은 기능에 대한 테스트를 작성한다. 즉, 먼저 원하는 기능이나 수정사항에 대한 실패하는 테스트 코드를 작성한다.
이 테스트는 처음에는 실패할 것인데, 왜냐하면 실제 구현이 아직 이루어지지 않았기 때문이다.
// add.js
// 아직 이 함수는 구현되지 않음
export function add(a, b) {
// 구현 부분
}
// add.test.js
import { add } from './add';
// 실패하는 테스트 작성
test('adds 1 + 2 to equal 3', () => {
expect(add(1, 2)).toBe(3);
});
// 테스트 실행 시 'add' 함수가 아직 구현되지 않았으므로 실패한다.
(2) 최소한의 코드 작성
실패하는 테스트를 통과시킬 수 있는 최소한의 코드를 작성한다. 즉, 복잡한 구현, 최적화, 추가 기능 등을 고려하지 않고 오직 테스트만을 통과시키는 목적으로 코드를 작성한다.(여기서 중요한 것은 테스트를 통과시키는 것에 초점을 맞추는 것이다.)
// add.js
// 최소한의 코드를 작성하여 테스트를 통과시킨다.
export function add(a, b) {
return a + b;
}
(3) 리팩토링
코드가 테스트를 통과하면, 코드를 깔끔하게 정리하고, 중복을 제거하며, 코드의 품질을 향상시킨다.
(1) 높은 코드 품질
TDD를 통해 작성된 코드는 대체로 더 안정적이며, 잠재적인 버그 발생 확률이 낮아진다.
(2) 리팩토링 용이
테스트 코드가 있기 때문에 코드 변경 시 안전하게 리팩토링을 진행할 수 있다.
(3) 명확한 요구 사항 이해
테스트를 먼저 작성하면 개발자가 요구 사항을 더 명확하게 이해하게 되며, 해당 기능의 목적과 동작 방식에 대한 통찰력을 얻을 수 있다.
Jest는 페이스북에서 개발한 JavaScript 테스팅 프레임워크로, 특히 React와 같은 프론트엔드 라이브러리/프레임워크에서 많이 사용된다.
npm install --save-dev jest
yarn add --dev jest
📌 TypeScript를 위한 추가적인 패키지 설치하기
yarn add --dev @types/jest
: Jest의 TypeScript 타입 정의
yarn add --dev ts-jest
:TypeScript 코드를 Jest에서 직접 테스트할 수 있게 해주는 도구
yarn add --dev jest-environment-jsdom
: Jest 테스트 환경에서 DOM API를 에뮬레이트하기 위한 설정. 웹 브라우저 환경에서 실행되는 JavaScript 코드를 Jest 환경에서 실행할 때 필요
yarn add --dev @testing-library/react
: React 컴포넌트를 테스트하기 위한 유틸리티. 이 라이브러리는 React 컴포넌트를 렌더링하고 결과를 쿼리할 수 있도록 도와줌
yarn add --dev @testing-library/jest-dom
: Jest에 DOM에 대한 사용자 친화적인 어설션( 특정 조건이 참인지 확인하는 데 사용되는 명령 또는 함수)을 추가. 이를 통해 DOM 요소의 특정 상태나 속성을 더 쉽게 테스트할 수 있음
yarn add --dev @testing-library/user-event
: 사용자의 이벤트(클릭, 입력 등)를 시뮬레이트하기 위한 도구. fireEvent보다 더 실제 사용자의 동작에 가까운 이벤트를 발생시킬 수 있음.
// package.json
"scripts": {
...
"test": "jest"
},
Jest는 기본적으로 .test.js
, .spec.js
, .test.ts
, 및 .spec.ts
확장자를 가진 파일들을 테스트 파일로 인식한다.
따라서 TypeScript로 작성된 테스트 코드를 사용할 때, 해당 파일의 확장자를 .test.ts
또는 .spec.ts
로 지정하면 Jest가 자동으로 해당 파일들을 테스트 파일로 인식하고 실행한다! 😀
// functions.js
export function add(a, b) {
return a + b;
}
// functions.test.js
import { add } from './functions';
test('add 1 + 2 to equal 3', () => {
expect(add(1, 2)).toBe(3);
});
npm test
yarn test
Jest 테스트 프레임워크에서 프로젝트의 테스트 설정을 정의하는 파일이다. 이 파일을 사용하여 Jest의 다양한 옵션과 설정을 구성할 수 있다.
jest.config.js에서 구성할 수 있는 일반적인 옵션
roots: Jest가 테스트 파일을 찾을 위치를 지정한다.
(ex. 테스트 파일이 src/tests/
디렉토리에 있다면, roots: ["<rootDir>/src/tests/"]
로 설정)
testEnvironment: 테스트 환경을 정의한다. (ex. node 또는 jsdom 등)
transform: 특정 파일 확장자를 처리하기 위한 변환 모듈을 지정한다. (ex. TypeScript 파일을 Jest에서 직접 처리할 때)
testRegex 또는 testMatch: 테스트 파일을 찾기 위한 정규식 또는 패턴을 지정한다.
moduleFileExtensions: 처리할 파일 확장자 목록을 지정한다.
setupFiles 또는 setupFilesAfterEnv: 테스트 실행 전에 특정 스크립트를 실행하도록 설정한다.
moduleNameMapper: 모듈 경로 별칭을 지정한다. 특히, 경로 별칭이나 특정 파일 확장자 (ex. .scss
또는 .png
)에 대한 목을 설정할 때 유용하다.
moduleNameMapper: {
"^@components/(.*)": "<rootDir>/src/components/$1", // '@components/Button' -> '/src/components/Button'
"\\.(css|less|scss)$": "identity-obj-proxy" // CSS 모듈을 위한 목
}
testPathIgnorePatterns: 테스트에서 무시해야 하는 경로 패턴 목록을 지정한다. (ex. ["/node_modules/", "/build/"]
)
transformIgnorePatterns: 변환에서 무시해야 하는 파일의 패턴 목록을 지정한다. 이 설정은 주로 node_modules
내의 모듈을 변환할 필요가 없을 때 유용하다.
watchPlugins: 테스트 중에 사용할 수 있는 명령 및 패널 UI를 제공하는 외부 플러그인 목록을 지정한다.
collectCoverage: 코드 커버리지 정보를 수집할지 여부를 지정한다. 보통 테스트 커버리지를 확인하고 싶을 때 true로 설정한다.
coverageThreshold: 코드 커버리지의 최소 허용치를 지정한다. 설정된 임계값보다 낮은 경우, Jest는 에러 코드와 함께 종료된다.
coverageReporters: 커버리지 리포트 형식을 지정한다. 자주 사용되는 값으로는 ["lcov", "text"]
등이 있다.
collectCoverageFrom: 커버리지를 수집할 파일 목록을 지정한다. 특정 파일이나 폴더를 제외하고 싶을 때 사용한다.
setupFilesAfterEnv: 각 테스트 파일 실행 전에 실행되어야 할 설정 파일 목록을 지정한다. (ex. 테스트 라이브러리의 추가 설정이나 테스트 유틸리티를 로드하는 데 사용)
mocks, spies, stubs: 테스트에 사용될 모킹, 스파이, 스텁을 설정한다.
// ex.)
module.exports = {
testEnvironment: "node",
transform: {
"^.+\\.tsx?$": "ts-jest"
},
testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
};
.ts
및 .tsx
확장자를 가진 파일을 ts-jest
를 사용하여 변환하도록 설정하며, 테스트 환경으로 node
를 사용하도록 설정
실제 구현이나 동작을 가진 객체, 함수, 모듈 등을 테스트를 위한 더미 객체로 대체하는 것이다.
주로 단위 테스트에서 외부 의존성을 가진 코드의 동작을 테스트할 때 사용된다.
모킹은 단위 테스트에서 특히 중요하다. 단위 테스트는 보통 개별 코드 모듈이나 함수의 동작을 테스트하는데, 이 때 해당 모듈이나 함수가 의존하는 외부 요소들을 실제로 사용하면 테스트의 복잡성이 증가하고, 테스트 실패 원인을 찾기 어려워질 수 있다.
이런 이유로, 테스트 대상 코드가 의존하는 요소들을 모킹해서 대체하게 된다.
모킹을 통해 테스트 대상 코드의 동작을 더 잘 제어하고, 테스트의 독립성과 격리를 유지할 수 있다.
또한, 모킹을 사용하면 실제 구현이 완료되지 않은 기능에 대한 테스트를 미리 작성하는 것도 가능하다.
예를 들어, 네트워크 API 호출을 하는 함수를 테스트한다고 할 때, 실제 네트워크 호출을 하지 않고 그 결과를 모킹하는 것이 일반적이다.
이를 통해 네트워크 연결 문제, 서버 문제 등 외부 요인으로 인한 테스트 실패를 방지하고, 함수가 API 응답을 올바르게 처리하는지에 초점을 맞출 수 있다.
JavaScript 및 TypeScript에서는 Jest와 같은 테스트 프레임워크를 사용하여 모킹을 쉽게 할 수 있다.
Jest는 함수 모킹, 타이머 모킹, 모듈 모킹 등 다양한 모킹 기능을 제공한다.
(1) 의존성 제거
코드가 데이터베이스, 네트워크, 하드웨어 등의 외부 시스템에 의존할 경우, 이러한 의존성을 제거하고 테스트를 단순화하기 위해 모킹을 사용한다.
(2) 검증
테스트 중에 특정 함수나 메서드가 예상대로 호출되었는지 검증한다.
(3) 특정 시나리오 재현
예를 들어, 네트워크 오류 또는 데이터베이스 연결 실패와 같은 예외적인 상황을 재현하여 테스트할 수 있다.