๊ฐ๋ ์ฑ ์ข์ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ
๊ฐ๋ ์ฑ ์ข์ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ ๊ด๋ จ
์ต๊ทผ ํ๋ก ํธ์๋ ์์ญ์์๋ ํ ์คํธ ์ฝ๋๋ฅผ ๋ง์ด ์์ฑํ๋ ํธ์ ๋๋ค. ํนํ ์ฑ์ฉ๊ณต๊ณ ๋ฅผ ๋๋ฌ๋ณด๋ฉด Cypress, Jest, testing-library ๋ฑ์ ํ ์คํธ ๊ธฐ์ ์ด ์ ํ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์์ง ํ๋ก ํธ์๋์์์ ํ ์คํธ ์ฝ๋๋ ๋ฐฑ์๋ ์์ญ๊ณผ ๋ฌ๋ฆฌ, ํ์ ๊ฐ๋ฐ ๋ฌธํ๋ก ์๋ฆฌ ์ก๊ฑฐ๋ ๊ฐ์ธ์ด ์ต์ํด์ง ์ ๋์ ๋จ๊ณ๋ ์๋ ๊ฒ ๊ฐ์๋ฐ์.
๊ทธ๋ฌ๋ค ๋ณด๋ ํ ์คํธ ์ฝ๋๋ฅผ ์ ๋ง๋ค์ ์คํ์ผ๋ก ์์ฑํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ๊ทธ๋ฌ๋ ํ ์คํธ ์ฝ๋๋ ๊ฐ๋ ์ฑ์ด ์ค์ํ ๋งํผ, ์ด๋ฒ ๊ธ์์๋ ํ ์คํธ ์ฝ๋๋ฅผ ์ด๋ป๊ฒ ์์ฑํด์ผ ๊ฐ๋ ์ฑ์ ๋์ผ ์ ์์์ง ํ ์คํธ ์ฝ๋ ์์ฑ ํ์ ๊ดํด ์ดํด๋ณด๊ณ ์ ํฉ๋๋ค.
ํ ์คํธ ์ฝ๋์ ์ญํ
๋จผ์ ํ ์คํธ ์ฝ๋ ์์ฑ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ธฐ ์ , ํ ์คํธ ์ฝ๋์ ์ญํ ์ด ๋ฌด์์ธ์ง ์์์ผ ํ๋๋ฐ์. ์ฐ๋ฆฌ๋ ์ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ ๊น์? ๊ทธ ์ด์ ๋ ์์ฑํ ์ฝ๋๊ฐ ์ ๋๋ก ๋์ํ๋์ง ๊ฒ์ฌํ๊ณ , ์ฝ๋๋ฅผ ์์ ํ ๋ ์์ํ์ง ๋ชปํ๋ ๋ฒ๊ทธ๋ฅผ ๋ฏธ๋ฆฌ ๋ฐ๊ฒฌํ๊ธฐ ์ํจ์ ๋๋ค. ์ด์ธ์๋ ํ ์คํธ ์ฝ๋๋ ๋ฌธ์๋ก์ ์ค์ํ ์ญํ ์ ํฉ๋๋ค.
์ฌ๋ฌ๋ถ์ด ๋๊ตฐ๊ฐ ์์ฑํ ํ ์คํธ ์ฝ๋๋ฅผ ์ฝ๋๋ค๊ณ ํ ๋, ๋ณต์กํ ํ ์คํธ ์ฝ๋๋ฅผ ์ํ๋ ์ฌ๋์ ์์ ๊ฒ์ ๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ๋ ๋์ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์๊น์? ์ง๊ธ๋ถํฐ ํ๋์ฉ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
ํ ์คํธ ์ฝ๋ ์ ๋ชฉ ์์ฑ ํ
ํ ์คํธ ์ฝ๋์์ ๊ฐ์ฅ ์ค์ํ ๋ถ๋ถ ์ค ํ๋๋ ์ ๋ชฉ์ ์ฌ๋ฐ๋ฅด๊ฒ ์์ฑํ๋ ๊ฒ์ธ๋ฐ์. ์ ๋ ํ ์คํธ ์ฝ๋ ์์ฑ๋ฒ์ ๋ฌป๋ ๋๋ฃ ๊ฐ๋ฐ์๋ค์๊ฒ ์ฑ ์ ๋ชฉ์ฐจ๋ฅผ ์ฐ๋ฏ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๋ผ๊ณ ์กฐ์ธํด ์ค๋๋ค.
A๋ฅผ ๋ง์กฑํ๋ฉด B๊ฐ ๋์ถ๋๋ ํ์์ผ๋ก ์์ฑํ๊ธฐ
์ฑ ์์ ๋ชฉ์ฐจ๋ ๋ด์ฉ๋งํผ์ด๋ ์ค์ํฉ๋๋ค. ์๊ฐ๊ฐ ์ด๋ค ๋ด์ฉ์ผ๋ก ์ฑ ์ ์ผ๋์ง ๋จ๋ฒ์ ์ ์ ์๊ธฐ ๋๋ฌธ์ด์ฃ . ํ ์คํธ ์ฝ๋๋ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค. ํ ์คํธ ์ฝ๋๋ โํ ์คํธ ์ ๋ชฉ๋ง์ผ๋ก ์ด๋ค ํ ์คํธ์ธ์ง ์ ์ ์์ด์ผโ ํฉ๋๋ค. ์๋ฌด๋ฆฌ ์ข์ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๋ค๊ณ ํด๋ ์ ๋ชฉ์ด ์ด์ํ๊ฑฐ๋ ์ดํดํ๊ธฐ ํ๋ค๋ค๋ฉด, ๋ค๋ฅธ ๊ฐ๋ฐ์๊ฐ ๊ฐ์ ์ฃผ์ ๋ก ์ค๋ณต๋ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ ์ง๋ ๋ชจ๋ฆ ๋๋ค.
๊ทธ๋์ ์ ๋ชฉ์ A๋ฅผ ๋ง์กฑํ๋ฉด B๊ฐ ๋์ถ๋๋ ํ์์ผ๋ก ์์ฑํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ์๋ ์์๋ฅผ ํตํด ์ดํด๋ณผ๊ฒ์.
// Bad
test("๊ตฌ๋งค ๋ฒํผ ํด๋ฆญ", () => {
render(<SignUpForm />);
const purchaseButton = screen.queryByTestId("data-submit-button")!;
const modal = screen.queryByTestId("modal");
expect(modal).not.toBeInDocument();
purchaseButton.click();
expect(modal).toBeInDocument();
})
// Good
test("๊ตฌ๋งค ๋ฒํผ์ ํด๋ฆญํ๋ฉด, ๋ชจ๋ฌ์ ๋์ด๋ค", () => {
render(<SignUpForm />);
const purchaseButton = screen.queryByTestId("data-submit-button")!;
const modal = screen.queryByTestId("modal");
expect(modal).not.toBeInDocument();
purchaseButton.click();
expect(modal).toBeInDocument();
})
์ ์ฌ๋ก์ ์ ๋ชฉ์ ๊ตฌ๋งค ๋ฒํผ์ ํด๋ฆญํ๋ฉด ๋ชจ๋ฌ์ด ๋์์ง๋ค๊ณ ๋ณ๊ฒฝํด ๋ณด์์ต๋๋ค. ํจ์ฌ ๋ ๋์ ์ ๋ค์ด์ค์ง ์๋์? ์ ๋ชฉ๋ง ๋ฐ๊ฟจ์ ๋ฟ์ธ๋ฐ ํจ์ฌ ์๊ธฐ ์ฌ์ด ํ ์คํธ๊ฐ ๋์์ต๋๋ค. ์์ง ํ ์คํธ ์ฝ๋ ์์ฑ์ด ๋ฏ์ค๋ค๋ฉด, ์ฐ์ ์ ๋ชฉ์ ๋ฐ๊พธ๋ ์ฐ์ต๋ถํฐ ํด๋ณด์๊ธธ ๋ฐ๋๋๋ค.
๋ถ๋ฅ๋ณ๋ก ๋๋ ์ ์์ฑํ๊ธฐ
ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๋ค ๋ณด๋ฉด, ์ฌ๋ฌ ์กฐ๊ฑด ์ค ํ ์คํธํ๋ ค๋ ์ธ๋ถ ๋ด์ฉ์ ์ ์ธํ ๋๋จธ์ง๋ ๊ฐ์ ๊ฒฝ์ฐ๋ ์์ ํ ๋ฐ์. ์๋ฅผ ๋ค์ด, ํ์๊ฐ์ ํผ์ ๋์ฐ๊ณ ๊ทธ ์์์ ์์ด๋์ ๋น๋ฐ๋ฒํธ๋ฅผ ์ ๋ ฅํ๋ ๊ฐ๊ฐ์ ํ ์คํธ๋ผ๋ฉด ํ์๊ฐ์ ํผ์ ๋์ฐ๋ ๊ฒ๊น์ง ๊ฐ์ ๋ด์ฉ์ด์ฃ . ๊ทธ๋์ ํ ์คํธ ์ฝ๋ ์ ๋ชฉ์ ๊ตฌ์ฒด์ ์ผ๋ก ์ ๋ค ๋ณด๋ฉด, ์ ๋ชฉ์ด ๊ธธ์ด์ ธ ์คํ๋ ค ๊ฐ๋ ์ฑ์ ํด์น์ง ์์๊น ์ฐ๋ ค๋๊ธฐ๋ ํฉ๋๋ค.
์ด๋ด ๋๋ ์ ๋ชฉ๊ณผ ์ฐ๊ด๋ ์ ์ ๋ถ๋ฅ๋ณ๋ก ๋๋๋ฉด ์ข์ต๋๋ค. ์ฑ ์ ๋ชฉ์ฐจ๋ ์ฑํฐ๊ฐ ์๊ณ , ๊ฐ ์ฑํฐ๋ณ๋ก ๋ค์ ์์ ๋ชฉ์ด ์๋ ๊ฒ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์๊ฐ์ ์ธ ํจ๊ณผ๋ฅผ ์ค ์ ์์ต๋๋ค.
// Bad
describe("SignUp Page", () => {
test("ํ์๊ฐ์
ํผ์ด ๋ ๋๋ง ๋ ๋, ์์ด๋๋์ด ๋น์ด์์ผ๋ฉด, ๋ฒํผ์ด ๋นํ์ฑํ๋์ด์ผ ํ๋ค", () => {
// โฆ
})
test("ํ์๊ฐ์
ํผ์ด ๋ ๋๋ง ๋ ๋, ๋น๋ฐ๋ฒํธ๋์ด ๋น์ด์์ผ๋ฉด, ๋ฒํผ์ด ๋นํ์ฑํ๋์ด์ผ ํ๋ค", () => {
// โฆ
})
})
// Good
describe("SignUp Page", () => {
describe("ํ์๊ฐ์
ํผ์ด ๋ ๋๋ง ๋ ๋", () => {
test("์์ด๋๋์ด ๋น์ด์์ผ๋ฉด, ๋ฒํผ์ด ๋นํ์ฑํ๋์ด์ผ ํ๋ค", () => {
// โฆ
})
test("๋น๋ฐ๋ฒํธ๋์ด ๋น์ด์์ผ๋ฉด, ๋ฒํผ์ด ๋นํ์ฑํ๋์ด์ผ ํ๋ค", () => {
// โฆ
})
})
})
์์ ๊ฐ์ด ์ ๋ชฉ์ ๋์ผํ ๋ถ๋ฅ๋ก ๋ฌถ์ด ์์์ ์์ฑํด ๋ดค์ต๋๋ค. ์ด์ฒ๋ผ ์ ๋ชฉ์ ์ ๋ถ๋ฅํ๋ ๊ฒ๋ง์ผ๋ก๋ ๊ฐ๋ ์ฑ์ ๊ฐ์ ํ ์ ์๋๋ฐ์.
ํ ๊ฐ์ง ํ์ ๊ณต์ ํด ๋ณผ๊ฒ์. ํ ์คํธ ์ ๋ชฉ์ ๊ฐ์ฅ ๋ฐ๊นฅ์ชฝ์ ์๋ 1๋ฒ๋ถํฐ ๋ค์ฌ์ฐ๊ธฐ๊ฐ ์ ์ฉ๋ ์ฐจ๋ก๋๋ก 2, 3๋ฒ์ ์์๋๋ก ์ฝ์์ ๋, ํ๋์ ๋ฌธ์ฅ์ผ๋ก ์์ฑ๋ ์ ์๊ฒ ๋ง๋ค๋ฉด ๊ฐ๋ ์ฑ์ด ์ข์์ง ์ ์์ต๋๋ค.
์์
- SignUp Page, ํ์๊ฐ์ ํผ์ด ๋ ๋๋ง ๋ ๋, ์์ด๋๋์ด ๋น์ด์์ผ๋ฉด, ๋ฒํผ์ด ๋นํ์ฑํ๋์ด์ผ ํ๋ค.
- SignUp Page, ํ์๊ฐ์ ํผ์ด ๋ ๋๋ง ๋ ๋, ๋น๋ฐ๋ฒํธ๋์ด ๋น์ด์์ผ๋ฉด, ๋ฒํผ์ด ๋นํ์ฑํ๋์ด์ผ ํ๋ค.
์๋ฒฝํ ๋ฌธ์ฅ์ ์๋๋๋ผ๋ ํ๋์ ๋ฌธ์ฅ์ผ๋ก ์ธ์ํ ์ ์๋ค๋ฉด ์ฑ๊ณต์ ๋๋ค.
Given-When-Then ๋ฒ์น ์ด์ฉํ๊ธฐ
ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ ๋ ๊ฐ๋จํ์ง๋ง ์์ฒญ๋ ํจ๊ณผ๋ฅผ ๊ฐ์ง ๋ฒ์น์ด ์์ต๋๋ค. ๋ฐ๋ก โGiven-When-Thenโ ํ ์คํธ ์ฝ๋ ๋ฒ์น์ ๋๋ค.
- Given: ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ํด ํ์ํ ๋ณ์๋ฅผ ์ ์ธํ๋ ์ค๋น ๊ณผ์
- When: ํ ์คํธ์ ํ์ํ ์ค๋น๋ฌผ(๋ณ์)์ ๊ฐ์ง๊ณ ์ด๋ฅผ ์ํํ๋ ค๋ ๋์(ํจ์)์ ํ ์คํธํ๋ ๊ณผ์
- Then: ์ํํ ํ ์คํธ์ ๊ดํ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ๋ ๊ณผ์
์ด๋ ๊ฒ 3๋จ๊ณ๋ก ์ด๋ค์ง ๊ฐ๋จํ ๋ฒ์น๋ง ์ ์ฉํด๋, ํ ์คํธ ์ฝ๋์ ๊ฐ๋ ์ฑ์ด ๋๋ผ์ธ ๋งํผ ์ข์์ง ์ ์์ต๋๋ค.
// ์ด๋ ๊ฒ ์์ฑํด ๋ณด์ธ์
describe("calculator", () => {
test("3 adds 5 equals 8", () => {
// Given - ํ
์คํธ์ ํ์ํ ์ค๋น๋ฌผ ์์ฑ
const num1 = 3;
const num2 = 5;
// When - ํ
์คํธ ๋์์ ์ํ
const result = add(num1, num2);
// Then - ๊ฒฐ๊ณผ๊ฐ ์ฌ๋ฐ๋ฅธ์ง ๊ฒ์ฆ
expect(result).toBe(num1 + num2);
})
})
์ ์์์ฒ๋ผ Given, When, Then์ ์ฃผ์๊ณผ ํจ๊ป ์์ญ์ ๋ถ๋ฆฌํด ์ฃผ๋ฉด ๊ฐ๋ ์ฑ์ด ๋์์ง๋๋ค. ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ ๋ ๊ธฐ๋ฅ์ด ๋ณต์กํด์ง๋ฉด, ์ฝ๋๋ 100~200์ค์ ๋์ด๊ฐ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์๋ฐ์. ์ด๋ด ๋ ์์ญ์ ํ์คํ๊ฒ ๋๋ ์ฃผ๋ฉด ์ฝ๊ธฐ๋ ์ฝ๊ณ , ๋์ค์ ์ ์ง๋ณด์๋ฅผ ๊ด๋ฆฌํ๊ธฐ์๋ ํธํฉ๋๋ค.
ํ ์คํธ ๋ฐ์ดํฐ๋ ๋์๋ฅผ ๋ง๋ค์ด ์ฌ์ฉํ๊ธฐ
๋๋ถ๋ถ ํ
์คํธ ์ฝ๋๋ฅผ ์์ฑํ ๋ ์์ ๊ฐ๋ฅํ ๋ณ์๋ ๊ฐ์ ๋ง๋ค์ด ์ฌ์ฉํ๋๋ฐ์. ๋ฐ๋ก ์์์ ์ดํด๋ณธ ์์์์๋ num1
๊ณผ num2
์ 3, 5๋ผ๋ ๊ฐ์ ์ง์ ํ ๋นํด ํ
์คํธํ์ต๋๋ค. ๊ทธ๋ ๋ค๋ฉด add
ํจ์๋ ์์๋ก ์ค์ ํ ์๋ก ๋ค๋ฅธ ๋ ๊ฐ A, B์ ๊ดํ ๋ชจ๋ ํ
์คํธ๋ฅผ ํต๊ณผํ ์ ์์๊น์? ๊ฐ๋ฐ์๊ฐ ํ
์คํธ ์ฝ๋๋ฅผ ์์ฑํ ๋ ์์ ๊ฐ๋ฅํ ๊ฐ์ผ๋ก๋ง ํ
์คํธํ๋ค๋ฉด, ์๊ธฐ์น ๋ชปํ ๋ฒ์์์ ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ ํ๋ฅ ์ ์ก์๋ด๊ธฐ ํ๋ค ๊ฒ์
๋๋ค. ๊ทธ๋์ ๋๋๋ก ๋์๋ฅผ ๋ง๋ค์ด์ ์ฌ์ฉํ๊ฑฐ๋, ์์ ๊ฐ์ ๋ถ๋ฌ์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ๋ฐ๋์งํฉ๋๋ค.
์ด๋ @faker-js/faker
๋ฅผ ์ฌ์ฉํ๋ฉด ์ํฉ๋ณ๋ก ์ ํฉํ ์์ ๊ฐ์ ๋ง๋ค ์ ์์ต๋๋ค. ํ
์คํธ์์๋ง ์ฌ์ฉํ๋ค๋ฉด ๊ฐ๋ฐ ์์กด์ฑ(devdependency)์ ํจํค์ง๋ฅผ ์ค์นํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
// faker.js ๋ฅผ ์ฌ์ฉํด ์์ ์์๋ฅผ ๋ค์ ์ฌ๊ตฌ์ฑํ์ต๋๋ค.
import { faker } from '@faker-js/faker';
describe("calculator", () => {
test("A adds B equals A+B", () => {
// Given - ํ
์คํธ์ ํ์ํ ์ค๋น๋ฌผ ์์ฑ
// faker.number.int ๋ ์์์ ์ ์๋ฅผ ์์ฑํฉ๋๋ค.
const num1 = faker.number.int();
const num2 = faker.number.int();
// When - ํ
์คํธ ๋์์ ์ํ
const result = add(num1, num2);
// Then - ๊ฒฐ๊ณผ๊ฐ ์ฌ๋ฐ๋ฅธ์ง ๊ฒ์ฆ
expect(result).toBe(num1 + num2);
})
})
์ฌ๊ธฐ์ ํ
์คํธ ์ ๋ชฉ๊น์ง ๋ณ๊ฒฝํด ์ฃผ๋ฉด ๋์ฑ ๋ฐ๋์งํ ํ
์คํธ๊ฐ ๋๊ฒ ์ฃ ? ์ด๋ ๋ฏ @faker-js/faker
๋ฅผ ์ฌ์ฉํ๋ฉด ํ
์คํธ๋ฅผ ์ํํ ๋๋ง๋ค ์์์ ์ ์๋ฅผ ๋ง๋ค์ด ํจ์๋ฅผ ํ
์คํธํ ์ ์์ต๋๋ค. ํญ์ ๊ฐ์ ์ผ์ด์ค๋ง ํ
์คํธํ๊ฒ ๋๋ค๋ฉด ๊ผญ ํ์ฉํด ๋ณด์๊ธฐ ๋ฐ๋๋๋ค.
๋ง์น๋ฉฐ
์ง๊ธ๊น์ง ์ด๋ป๊ฒ ํ๋ฉด ๋ ๋ช ํํ๊ณ ๊ฐ๋ ์ฑ ๋์ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์์ง ๋ช ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ดํด๋ณด์์ต๋๋ค. ์ด์ธ์๋ ์ฌ๋ฌ ๋ฐฉ๋ฒ์ด ์๊ฒ ์ง๋ง, ์ ๊ฐ ์๋ํด ๋ณธ ๊ฒฐ๊ณผ ์ต์ํ์ ๋ ธ๋ ฅ์ผ๋ก ์ต๋ํ์ ํจ๊ณผ๋ฅผ ์ป์ ์ ์์๋ ๋ฐฉ๋ฒ ์์ฃผ๋ก ์๊ฐํด ๋ณด์๋๋ฐ์. ์ด๋ฅผ ์ฐธ๊ณ ํด ์ค์ ํ ์คํธ ์ฝ๋์ ์ ์ฉํด ๋ณด๋ฉด์, ์ฌ๋ฌ๋ถ๋ ๋ณธ์ธ๋ง์ ํ ์คํธ ์ฝ๋ ์์ฑ ๋ ธํ์ฐ๋ฅผ ๋ง๋ค์ด ๊ฐ ์ ์๊ธธ ๋ฐ๋๋๋ค.