테스트 사례와 오라클
전제·입력·기대 결과·상태를 가진 사례를 작성하고 요구에서 도출한 오라클을 독립적으로 확인합니다.
개발자가 함수의 출력과 똑같은 값을 테스트의 정답으로 복사하면 오류도 정답이 될 수 있습니다. 테스트를 만들 때 먼저 알아야 하는 것은 실행 방법보다 무엇을 옳다고 판단할지입니다.
테스트 사례는 전제, 입력, 실행 행동, 기대 결과를 묶은 검증 단위입니다. 테스트 오라클은 실제 결과가 옳은지 판단하는 근거입니다. 이 교재에서는 수락 조건과 불변 조건이 근거가 됩니다.
사례를 쪼개 읽기
| 항목 | 중복 신청 사례 |
|---|---|
| 전제 | OPEN, 정원 1, 참가자 min |
| 입력·행동 | min 신청 |
| 기대 코드 | ALREADY_REGISTERED |
| 기대 상태 | 참가자 min, 원래 상태 유지 |
| 근거 | 열린 모임에서는 중복 검사 R3이 정원 검사 R4보다 우선 |
실제 출력의 문자열만 확인하면 참가자가 두 번 추가된 결함을 놓칩니다. 성공 코드와 새 명단, 실패 코드와 보존 상태를 함께 확인합니다. ok와 code가 서로 충돌하는 결과도 검토할 수 있습니다.
처음 만드는 자동 테스트
reading-lab/core.test.mjs에 저장합니다. core.mjs는 기능 요구 문서의 파일을 사용합니다.
import test from "node:test";
import assert from "node:assert/strict";
import { createSession, register } from "./core.mjs";
test("자리 있는 첫 신청은 등록하고 이전 상태는 보존한다", () => {
const before = createSession({ id: "book-1", title: "첫 책", capacity: 1 });
const result = register(before, "min");
assert.equal(result.code, "REGISTERED");
assert.deepEqual(result.state.participants, ["min"]);
assert.deepEqual(before.participants, []);
});
test("열린 만석 모임의 같은 ID는 중복으로 거절한다", () => {
const initial = createSession({ id: "book-1", title: "첫 책", capacity: 1 });
const before = register(initial, "min").state;
const result = register(before, "min");
assert.equal(result.code, "ALREADY_REGISTERED");
assert.equal(result.state, before);
});node --test core.test.mjs각 test는 다른 사례의 변경된 상태를 공유하지 않고 새 전제를 만듭니다. equal은 값 또는 객체 정체성을 비교하고 deepEqual은 배열 내부 값을 비교합니다. 오류가 발생하면 해당 사례가 실패합니다. 테스트 이름은 확인할 행동과 조건을 함께 설명합니다. Node.js 내장 테스트 실행 방법은 공식 문서에 설명되어 있습니다.
저장소의 core.test.mjs에는 취소·마감·복원까지 확장한 테스트가 들어 있습니다. 전체 통과 수를 외우지 말고 자신이 추가한 요구에 대응하는 사례가 있는지 확인합니다.
결함을 만드는 실험
작업용 복사본에서 정원 검사를 중복 검사 앞으로 옮겨 봅니다. 두 번째 사례가 실패해야 합니다. 이처럼 일부러 작은 결함을 주입하고 테스트가 발견하는지 확인하는 발상은 테스트의 감지 능력을 평가하는 데 도움이 됩니다. 원래 파일을 되돌린 다음 다시 실행합니다.
실패했다고 항상 제품 코드가 틀린 것은 아닙니다. 전제가 잘못됐거나 기대 결과가 이전 정책일 수 있습니다. 실패 원인 → 요구 근거 → 재현 자료 순서로 확인합니다. 무조건 기대 값을 현재 출력에 맞추면 오라클이 사라집니다.
독립 문제: 상태를 확인하지 않은 테스트
register가 FULL을 반환하면서 명단에 jun을 추가하는 결함이 있습니다. code만 확인하는 테스트는 통과합니다. 이 결함을 발견할 전제와 두 개의 단언문을 작성하세요.
힌트
새 ID가 들어갈 수 없는 전제를 만든 다음 이전 상태와 반환 상태를 확인합니다.
해설
정원 1, OPEN, 참가자 min에서 jun을 신청합니다. assert.equal(result.code, "FULL")와 assert.deepEqual(result.state.participants, ["min"])를 확인합니다. 이 코어가 실패할 때 같은 객체를 반환한다는 약속까지 확인하려면 assert.equal(result.state, before)를 추가합니다. 단순한 값 불변 정책만 있는 다른 구현이라면 객체 정체성 조건을 요구 없이 강제하지 않습니다.
몇 가지 사례를 통과했다고 결함이 없다고 결론 내리지 않습니다. 다음 문서는 입력 공간을 나누어 빠진 영역을 찾습니다.