메모 등록에 값의 범위, 필수 값 누락 등에 대한 테스트 진행
코드
const { createMemo } = require("../../src/memo/createMemo");
describe("createMemo", () => {
const validInput = {
title: "TDD 메모 작성",
period: {
startDate: "2026-03-06",
endDate: "2026-03-10",
},
content: "Red 단계 테스트 작성",
priority: 3,
};
test("정상 입력이면 memo 생성에 성공한다", async () => {
const result = await createMemo(validInput);
expect(result).toMatchObject({
title: "TDD 메모 작성",
period: {
startDate: "2026-03-06",
endDate: "2026-03-10",
},
content: "Red 단계 테스트 작성",
priority: 3,
isSuccess: false,
});
});
test("title이 없으면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
title: "",
}),
).rejects.toThrow("title");
});
test("title이 공백만 있으면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
title: " ",
}),
).rejects.toThrow("title");
});
test("title이 문자열이 아니면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
title: 1234,
}),
).rejects.toThrow("title");
});
test("period가 없으면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
period: null,
}),
).rejects.toThrow("period");
});
test("period의 startDate가 없으면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
period: {
endDate: "2026-03-10",
},
}),
).rejects.toThrow("period");
});
test("period의 endDate가 없으면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
period: {
startDate: "2026-03-06",
},
}),
).rejects.toThrow("period");
});
test("기간 시작일이 종료일보다 뒤면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
period: {
startDate: "2026-03-11",
endDate: "2026-03-10",
},
}),
).rejects.toThrow("period");
});
test("period 날짜 형식이 올바르지 않으면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
period: {
startDate: "wrong-date",
endDate: "2026-03-10",
},
}),
).rejects.toThrow("period");
});
test("content가 없으면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
content: "",
}),
).rejects.toThrow("content");
});
test("content가 공백만 있으면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
content: " ",
}),
).rejects.toThrow("content");
});
test("content가 문자열이 아니면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
content: 1234,
}),
).rejects.toThrow("content");
});
test("priority가 없으면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
priority: undefined,
}),
).rejects.toThrow("priority");
});
test("priority가 숫자가 아니면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
priority: "3",
}),
).rejects.toThrow("priority");
});
test("priority가 1보다 작으면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
priority: 0,
}),
).rejects.toThrow("priority");
});
test("priority가 5보다 크면 에러 발생", async () => {
await expect(
createMemo({
...validInput,
priority: 6,
}),
).rejects.toThrow("priority");
});
});
실행 로그
hongseongchae@hongseongchaeui-MacBookPro tdd_study % npm test
> tdd_study@1.0.0 test
> jest
FAIL __test__/memo/createMemo.test.js
● createMemo › 정상 입력이면 memo 생성에 성공한다
TypeError: createMemo is not a function
13 |
14 | test("정상 입력이면 memo 생성에 성공한다", async () => {
> 15 | const result = await createMemo(validInput);
| ^
16 |
17 | expect(result).toMatchObject({
18 | title: "TDD 메모 작성",
at Object.createMemo (__test__/memo/createMemo.test.js:15:26)
● createMemo › title이 없으면 에러 발생
TypeError: createMemo is not a function
29 | test("title이 없으면 에러 발생", async () => {
30 | await expect(
> 31 | createMemo({
| ^
32 | ...validInput,
33 | title: "",
34 | }),
at Object.createMemo (__test__/memo/createMemo.test.js:31:7)
● createMemo › title이 공백만 있으면 에러 발생
TypeError: createMemo is not a function
38 | test("title이 공백만 있으면 에러 발생", async () => {
39 | await expect(
> 40 | createMemo({
| ^
41 | ...validInput,
42 | title: " ",
43 | }),
at Object.createMemo (__test__/memo/createMemo.test.js:40:7)
● createMemo › title이 문자열이 아니면 에러 발생
TypeError: createMemo is not a function
47 | test("title이 문자열이 아니면 에러 발생", async () => {
48 | await expect(
> 49 | createMemo({
| ^
50 | ...validInput,
51 | title: 1234,
52 | }),
at Object.createMemo (__test__/memo/createMemo.test.js:49:7)
● createMemo › period가 없으면 에러 발생
TypeError: createMemo is not a function
56 | test("period가 없으면 에러 발생", async () => {
57 | await expect(
> 58 | createMemo({
| ^
59 | ...validInput,
60 | period: null,
61 | }),
at Object.createMemo (__test__/memo/createMemo.test.js:58:7)
● createMemo › period의 startDate가 없으면 에러 발생
TypeError: createMemo is not a function
65 | test("period의 startDate가 없으면 에러 발생", async () => {
66 | await expect(
> 67 | createMemo({
| ^
68 | ...validInput,
69 | period: {
70 | endDate: "2026-03-10",
at Object.createMemo (__test__/memo/createMemo.test.js:67:7)
● createMemo › period의 endDate가 없으면 에러 발생
TypeError: createMemo is not a function
76 | test("period의 endDate가 없으면 에러 발생", async () => {
77 | await expect(
> 78 | createMemo({
| ^
79 | ...validInput,
80 | period: {
81 | startDate: "2026-03-06",
at Object.createMemo (__test__/memo/createMemo.test.js:78:7)
● createMemo › 기간 시작일이 종료일보다 뒤면 에러 발생
TypeError: createMemo is not a function
87 | test("기간 시작일이 종료일보다 뒤면 에러 발생", async () => {
88 | await expect(
> 89 | createMemo({
| ^
90 | ...validInput,
91 | period: {
92 | startDate: "2026-03-11",
at Object.createMemo (__test__/memo/createMemo.test.js:89:7)
● createMemo › period 날짜 형식이 올바르지 않으면 에러 발생
TypeError: createMemo is not a function
99 | test("period 날짜 형식이 올바르지 않으면 에러 발생", async () => {
100 | await expect(
> 101 | createMemo({
| ^
102 | ...validInput,
103 | period: {
104 | startDate: "wrong-date",
at Object.createMemo (__test__/memo/createMemo.test.js:101:7)
● createMemo › content가 없으면 에러 발생
TypeError: createMemo is not a function
111 | test("content가 없으면 에러 발생", async () => {
112 | await expect(
> 113 | createMemo({
| ^
114 | ...validInput,
115 | content: "",
116 | }),
at Object.createMemo (__test__/memo/createMemo.test.js:113:7)
● createMemo › content가 공백만 있으면 에러 발생
TypeError: createMemo is not a function
120 | test("content가 공백만 있으면 에러 발생", async () => {
121 | await expect(
> 122 | createMemo({
| ^
123 | ...validInput,
124 | content: " ",
125 | }),
at Object.createMemo (__test__/memo/createMemo.test.js:122:7)
● createMemo › content가 문자열이 아니면 에러 발생
TypeError: createMemo is not a function
129 | test("content가 문자열이 아니면 에러 발생", async () => {
130 | await expect(
> 131 | createMemo({
| ^
132 | ...validInput,
133 | content: 1234,
134 | }),
at Object.createMemo (__test__/memo/createMemo.test.js:131:7)
● createMemo › priority가 없으면 에러 발생
TypeError: createMemo is not a function
138 | test("priority가 없으면 에러 발생", async () => {
139 | await expect(
> 140 | createMemo({
| ^
141 | ...validInput,
142 | priority: undefined,
143 | }),
at Object.createMemo (__test__/memo/createMemo.test.js:140:7)
● createMemo › priority가 숫자가 아니면 에러 발생
TypeError: createMemo is not a function
147 | test("priority가 숫자가 아니면 에러 발생", async () => {
148 | await expect(
> 149 | createMemo({
| ^
150 | ...validInput,
151 | priority: "3",
152 | }),
at Object.createMemo (__test__/memo/createMemo.test.js:149:7)
● createMemo › priority가 1보다 작으면 에러 발생
TypeError: createMemo is not a function
156 | test("priority가 1보다 작으면 에러 발생", async () => {
157 | await expect(
> 158 | createMemo({
| ^
159 | ...validInput,
160 | priority: 0,
161 | }),
at Object.createMemo (__test__/memo/createMemo.test.js:158:7)
● createMemo › priority가 5보다 크면 에러 발생
TypeError: createMemo is not a function
165 | test("priority가 5보다 크면 에러 발생", async () => {
166 | await expect(
> 167 | createMemo({
| ^
168 | ...validInput,
169 | priority: 6,
170 | }),
at Object.createMemo (__test__/memo/createMemo.test.js:167:7)
Test Suites: 1 failed, 1 total
Tests: 16 failed, 16 total
Snapshots: 0 total
Time: 1.01 s
Red인 경우 테스트 코드를 정의하는 단계(실패하는 케이스)이므로 코드가 구현되어있지않으므로 모두 실패로 나온다.
Red를 바탕으로 실행 코드를 작성한다
코드
async function createMemo(input) {
const { title, period, content, priority } = input;
if (typeof title !== "string" || title.trim() === "") {
throw new Error("title");
}
if (
!period ||
typeof period.startDate !== "string" ||
typeof period.endDate !== "string"
) {
throw new Error("period");
}
const start = new Date(period.startDate);
const end = new Date(period.endDate);
if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) {
throw new Error("period");
}
if (start > end) {
throw new Error("period");
}
if (typeof content !== "string" || content.trim() === "") {
throw new Error("content");
}
if (typeof priority !== "number" || priority < 1 || priority > 5) {
throw new Error("priority");
}
return {
title,
period,
content,
priority,
isSuccess: false,
};
}
module.exports = { createMemo };
실행 로그
hongseongchae@hongseongchaeui-MacBookPro tdd_study % npm test
> tdd_study@1.0.0 test
> jest
PASS __test__/memo/createMemo.test.js
createMemo
✓ 정상 입력이면 memo 생성에 성공한다 (3 ms)
✓ title이 없으면 에러 발생 (8 ms)
✓ title이 공백만 있으면 에러 발생 (3 ms)
✓ title이 문자열이 아니면 에러 발생 (1 ms)
✓ period가 없으면 에러 발생
✓ period의 startDate가 없으면 에러 발생 (1 ms)
✓ period의 endDate가 없으면 에러 발생 (1 ms)
✓ 기간 시작일이 종료일보다 뒤면 에러 발생 (1 ms)
✓ period 날짜 형식이 올바르지 않으면 에러 발생 (1 ms)
✓ content가 없으면 에러 발생
✓ content가 공백만 있으면 에러 발생 (1 ms)
✓ content가 문자열이 아니면 에러 발생
✓ priority가 없으면 에러 발생
✓ priority가 숫자가 아니면 에러 발생 (1 ms)
✓ priority가 1보다 작으면 에러 발생 (1 ms)
✓ priority가 5보다 크면 에러 발생
Test Suites: 1 passed, 1 total
Tests: 16 passed, 16 total
Snapshots: 0 total
Time: 0.215 s, estimated 1 s
Ran all test suites.
Green을 통과한 기준으로 refactoring를 진행한다.
검증함수 분리
코드
function validateTitle(title) {
if (typeof title !== "string" || title.trim() === "") {
throw new Error("title");
}
}
function validateContent(content) {
if (typeof content !== "string" || content.trim() === "") {
throw new Error("content");
}
}
function validatePriority(priority) {
if (typeof priority !== "number" || priority < 1 || priority > 5) {
throw new Error("priority");
}
}
function validatePeriod(period) {
if (
!period ||
typeof period.startDate !== "string" ||
typeof period.endDate !== "string"
) {
throw new Error("period");
}
if (!isValidDateRange(period.startDate, period.endDate)) {
throw new Error("period");
}
}
function isValidDateRange(startDate, endDate) {
const start = new Date(startDate);
const end = new Date(endDate);
if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) {
return false;
}
if (start > end) {
return false;
}
return true;
}
async function createMemo(input) {
const { title, period, content, priority } = input;
validateTitle(title);
validatePeriod(period);
validateContent(content);
validatePriority(priority);
return {
title,
period,
content,
priority,
isSuccess: false,
};
}
module.exports = { createMemo };
실행 로그
hongseongchae@hongseongchaeui-MacBookPro tdd_study % npm test
> tdd_study@1.0.0 test
> jest
PASS __test__/memo/createMemo.test.js
createMemo
✓ 정상 입력이면 memo 생성에 성공한다 (3 ms)
✓ title이 없으면 에러 발생 (8 ms)
✓ title이 공백만 있으면 에러 발생 (1 ms)
✓ title이 문자열이 아니면 에러 발생 (1 ms)
✓ period가 없으면 에러 발생 (1 ms)
✓ period의 startDate가 없으면 에러 발생 (1 ms)
✓ period의 endDate가 없으면 에러 발생 (1 ms)
✓ 기간 시작일이 종료일보다 뒤면 에러 발생 (1 ms)
✓ period 날짜 형식이 올바르지 않으면 에러 발생 (1 ms)
✓ content가 없으면 에러 발생 (1 ms)
✓ content가 공백만 있으면 에러 발생 (2 ms)
✓ content가 문자열이 아니면 에러 발생 (1 ms)
✓ priority가 없으면 에러 발생
✓ priority가 숫자가 아니면 에러 발생 (1 ms)
✓ priority가 1보다 작으면 에러 발생
✓ priority가 5보다 크면 에러 발생
Test Suites: 1 passed, 1 total
Tests: 16 passed, 16 total
Snapshots: 0 total
Time: 0.339 s, estimated 1 s
Ran all test suites.