원래 파이썬으로 알고리즘 문제를 풀 때
테스트를 해보기 위해서 input 값을 주석처리하고
입력값을 담는 변수에 직접 값들을 넣어서 테스트하곤 했는데
Jest를 사용하면 그런 수고를 덜 수 있고, 더 다양한 테스트를 쉽게 해볼 수 있다.
그런 의미에서 생소했던 Jest 개념과 각각 코드들을 뜯어보면서 이해하는 시간을 가져봤다.
Jest란?
- 자바스크립트 테스트 도구
- 코드가 예상대로 동작하는지 확인하기 위해 사용
- 이 함수가 주어진 입력에 대해 정확히 어떤 결과를 출력하는가? 를 자동으로 검사할 수 있음
import App from "../src/App.js";
import { MissionUtils } from "@woowacourse/mission-utils";
const mockQuestions = (inputs) => {
MissionUtils.Console.readLineAsync = jest.fn();
MissionUtils.Console.readLineAsync.mockImplementation(() => {
const input = inputs.shift();
return Promise.resolve(input);
});
};
const getLogSpy = () => {
const logSpy = jest.spyOn(MissionUtils.Console, "print");
logSpy.mockClear();
return logSpy;
};
describe("문자열 계산기", () => {
test("커스텀 구분자 사용", async () => {
const inputs = ["//;\\\\n1"];
mockQuestions(inputs);
const logSpy = getLogSpy();
const outputs = ["결과 : 1"];
const app = new App();
await app.run();
outputs.forEach((output) => {
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining(output));
});
});
test("예외 테스트", async () => {
const inputs = ["-1,2,3"];
mockQuestions(inputs);
const app = new App();
await expect(app.run()).rejects.toThrow("[ERROR]");
});
});
- `describe` : 테스트 그룹, 관련 테스트들을 묶는 블록
- `test()` : 실제 테스트 단위, 한 가지 상황을 검사 (기능 테스트)
- `expect()` : 테스트의 결과를 확인하는 부분
- `mockQuestions` : 사용자 입력 흉내
mockQuestions 함수
const mockQuestions = (inputs) => {
MissionUtils.Console.readLineAsync = jest.fn();
MissionUtils.Console.readLineAsync.mockImplementation(() => {
const input = inputs.shift();
return Promise.resolve(input);
});
};
- 실제 사용자 입력(`readLineAsync`) 대신 테스트용 입력을 흉내 냄
- `inputs.shift()` : 배열에서 첫 번째 값을 꺼내서 사용
- `Promise.resolve(input`) : `await`로 받을 수 있도록 비동기 처리
- 즉, 사용자가 입력한 것처럼 프로그램이 동작하게 만드는 가짜 입력 장치
getLogSpy 함수
const getLogSpy = () => {
const logSpy = jest.spyOn(MissionUtils.Console, "print");
logSpy.mockClear();
return logSpy;
};
- `MissionUtils.Console.print` 가 호출될 때 무엇을 출력했는지 감시
- `logSpy` : 출력된 모든 문자열 기록
- 나중에 `expect(logSpy).toHaveBeenCalledWith(…)` 로 예상 출력과 비교
describe와 test
describe("문자열 계산기", () => {
test("커스텀 구분자 사용", async () => { ... });
test("예외 테스트", async () => { ... });
});
- `decribe` : 관련 테스트 케이스 묶음
- `test` : 개별 테스트 시나리오
- “커스텀 구분자 사용” : 정상 입력 테스트
- “예외 테스트” : 음수 입력 같은 오류 테스트
정상 동작 테스트
const inputs = ["//;\\\\n1"];
mockQuestions(inputs);
const logSpy = getLogSpy();
const outputs = ["결과 : 1"];
const app = new App();
await app.run();
outputs.forEach((output) => {
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining(output));
});
- mockQuestions(inputs) : 테스트 입력 준비
- logSpy = getLogSpy() : 출력 감시
- app.run() : 프로그램 실행
- expect(logSpy).toHaveBeenCalledWith(...) : 출력에 “결과 : 1” 이 포함되는지 확인
즉, 입력 `//;\\n1` → 계산 결과`"결과 : 1"` 출력 → 테스트 통과
예외 테스트
const inputs = ["-1,2,3"];
mockQuestions(inputs);
const app = new App();
await expect(app.run()).rejects.toThrow("[ERROR]");
- 음수 입력(-1) : 예외 발생 예상
- `await expect(app.run()).rejects.toThrow("[ERROR]");`
- `run()` 실행시 예외가 발생하는지 확인
- 예외 메시지에 [ERROR]가 포함되어야 통과
- 출력이나 내부 계산을 보지 않고 예외 발생 여부만 확인
짜잘이 함수들 이해
1. `expect`
- 이 값이 예상과 일치하는지 검증 하는 함수
- 테스트에서 핵심: 결과가 내가 예상한 값과 같아야 함
const result = 1 + 2;
expect(result).toBe(3); // result가 3이어야 통과
- `toBe` : 정확히 같은 값인지 확인
expect([1,2,3]).toEqual([1,2,3]); // 통과
expect([1,2,3]).toBe([1,2,3]); // 실패 (참조가 다름)
- `toEqual` : 객체나 배열 등 구조가 같은지 확인
2. `rejects`
- 비동기 함수(async)에서 예외가 발생할 것을 검증할 때 사용
- await expect(…).rejects.toThrow() 형태로 쓰임
async function failFunc() {
throw new Error("[ERROR]");
}
await expect(failFunc()).rejects.toThrow("[ERROR]");
- failFunc()가 예외를 던져야 통과
- "[ERROR]" 메시지가 포함되어야 통과
3. `toHaveBeenCalledWith`
- 함수가 특정 인자를 가지고 호출되었는지를 검증
- 보통 모의 함수(mock function)와 함께 사용
const mockFn = jest.fn();
mockFn(1, 2);
expect(mockFn).toHaveBeenCalledWith(1, 2); // 통과
- mockFn이 1,2 인자로 호출되었는가? 확인
- 출력 감시(spy)에도 사용 가능
const logSpy = jest.spyOn(console, "log");
console.log("Hello");
expect(logSpy).toHaveBeenCalledWith("Hello"); // 통과
4. `stringContaining`과 조합
- 문자열의 일부분만 확인할 때
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("결과 : 1"));
- 로그 전체가 “결과 : 1” 일 필요는 없음
- “결과 : 1” 등 일부 포함만 되어도 통과
'etc' 카테고리의 다른 글
| [2025년 회고록] 나의 20대 초반을 보내주면서... (0) | 2025.12.31 |
|---|---|
| 🏀 Basketball Coach 성능 최적화 기록 (0) | 2025.11.26 |
| 인삿말 (7) | 2024.11.04 |