ํ๋ก ํธ์๋ ํ ์คํธ ํผ๋ผ๋ฏธ๋(๋จ์, ํตํฉ, ์๋ํฌ์๋(E2E) ํ ์คํธ)์ ๋ํ ์ข ํฉ ๊ฐ์ด๋์ ๋๋ค. ํ๋ ฅ ์๊ณ ์ ๋ขฐํ ์ ์๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก์ ์ ๋ต์ ์์๋ณด์ธ์.
ํ๋ก ํธ์๋ ํ ์คํธ ํผ๋ผ๋ฏธ๋: ๊ฒฌ๊ณ ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ ๋จ์, ํตํฉ, E2E ์ ๋ต
์ค๋๋ ๋น ๋ฅด๊ฒ ๋ณํํ๋ ์ํํธ์จ์ด ๊ฐ๋ฐ ํ๊ฒฝ์์ ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ง๊ณผ ์ ๋ขฐ์ฑ์ ๋ณด์ฅํ๋ ๊ฒ์ ๋ฌด์๋ณด๋ค ์ค์ํฉ๋๋ค. ์ ๊ตฌ์กฐํ๋ ํ ์คํธ ์ ๋ต์ ๋ฒ๊ทธ๋ฅผ ์กฐ๊ธฐ์ ๋ฐ๊ฒฌํ๊ณ , ํ๊ท(regression)๋ฅผ ๋ฐฉ์งํ๋ฉฐ, ์ํํ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ๋ ๋ฐ ํ์์ ์ ๋๋ค. ํ๋ก ํธ์๋ ํ ์คํธ ํผ๋ผ๋ฏธ๋๋ ํ ์คํธ ๋ ธ๋ ฅ์ ์ฒด๊ณํํ๊ณ ํจ์จ์ฑ์ ์ด์ ์ ๋ง์ถ๋ฉฐ ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ๊ทน๋ํํ๋ ๋ฐ ์ ์ฉํ ํ๋ ์์ํฌ๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด ์ข ํฉ ๊ฐ์ด๋์์๋ ํผ๋ผ๋ฏธ๋์ ๊ฐ ๊ณ์ธต์ธ ๋จ์, ํตํฉ, ์๋ํฌ์๋(E2E) ํ ์คํธ์ ๋ํด ๊น์ด ํ๊ณ ๋ค์ด ๊ฐ ํ ์คํธ์ ๋ชฉ์ , ์ด์ ๋ฐ ์ค์ ๊ตฌํ ๋ฐฉ๋ฒ์ ์ดํด๋ด ๋๋ค.
ํ ์คํธ ํผ๋ผ๋ฏธ๋์ ์ดํด
๋ง์ดํฌ ์ฝ(Mike Cohn)์ ์ํด ์ฒ์ ๋์คํ๋ ํ ์คํธ ํผ๋ผ๋ฏธ๋๋ ์ํํธ์จ์ด ํ๋ก์ ํธ์์ ์ด์์ ์ธ ์ ํ๋ณ ํ ์คํธ ๋น์จ์ ์๊ฐ์ ์ผ๋ก ๋ํ๋ ๋๋ค. ํผ๋ผ๋ฏธ๋์ ๊ธฐ๋ฐ์ ๋ค์์ ๋จ์ ํ ์คํธ๋ก ๊ตฌ์ฑ๋๋ฉฐ, ๊ทธ ์๋ก ๋ ์ ์ ์์ ํตํฉ ํ ์คํธ, ๊ทธ๋ฆฌ๊ณ ๋งจ ์์๋ ์์์ E2E ํ ์คํธ๊ฐ ์์นํฉ๋๋ค. ์ด๋ฌํ ๋ชจ์์ ๊ทผ๊ฑฐ๋ ๋จ์ ํ ์คํธ๊ฐ ์ผ๋ฐ์ ์ผ๋ก ํตํฉ ๋ฐ E2E ํ ์คํธ์ ๋นํด ์์ฑ, ์คํ, ์ ์ง ๊ด๋ฆฌ๊ฐ ๋ ๋น ๋ฅด๊ธฐ ๋๋ฌธ์ ํฌ๊ด์ ์ธ ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ๋ฌ์ฑํ๋ ๋ฐ ๋ ๋น์ฉ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ด๋ผ๋ ๊ฒ์ ๋๋ค.
์๋ ํผ๋ผ๋ฏธ๋๋ ๋ฐฑ์๋ ๋ฐ API ํ ์คํธ์ ์ค์ ์ ๋์์ง๋ง, ๊ทธ ์์น์ ํ๋ก ํธ์๋์๋ ์ฝ๊ฒ ์ ์ฉ๋ ์ ์์ต๋๋ค. ๊ฐ ๊ณ์ธต์ด ํ๋ก ํธ์๋ ๊ฐ๋ฐ์ ์ด๋ป๊ฒ ์ ์ฉ๋๋์ง๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ๋จ์ ํ ์คํธ: ๊ฐ๋ณ ์ปดํฌ๋ํธ๋ ํจ์์ ๊ธฐ๋ฅ์ ๋ ๋ฆฝ์ ์ผ๋ก ๊ฒ์ฆํฉ๋๋ค.
- ํตํฉ ํ ์คํธ: ์ปดํฌ๋ํธ๋ ๋ชจ๋๊ณผ ๊ฐ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ๋ฌ ๋ถ๋ถ์ด ํจ๊ป ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํฉ๋๋ค.
- E2E ํ ์คํธ: ์ค์ ์ฌ์ฉ์ ์ํธ์์ฉ์ ์๋ฎฌ๋ ์ด์ ํ์ฌ ์ฒ์๋ถํฐ ๋๊น์ง ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ํ๋ฆ์ ๊ฒ์ฆํฉ๋๋ค.
ํ ์คํธ ํผ๋ผ๋ฏธ๋ ์ ๊ทผ ๋ฐฉ์์ ์ฑํํ๋ฉด ํ์ด ํ ์คํธ ๋ ธ๋ ฅ์ ์ฐ์ ์์๋ฅผ ์ ํ๊ณ , ๊ฐ์ฅ ํจ์จ์ ์ด๊ณ ์ํฅ๋ ฅ ์๋ ํ ์คํธ ๋ฐฉ๋ฒ์ ์ง์คํ์ฌ ๊ฒฌ๊ณ ํ๊ณ ์ ๋ขฐํ ์ ์๋ ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
๋จ์ ํ ์คํธ: ํ์ง์ ๊ธฐ์ด
๋จ์ ํ ์คํธ๋ ๋ฌด์์ธ๊ฐ?
๋จ์ ํ ์คํธ๋ ํจ์, ์ปดํฌ๋ํธ, ๋ชจ๋๊ณผ ๊ฐ์ ์ฝ๋์ ๊ฐ๋ณ ๋จ์๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ํ ์คํธํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค. ๋ชฉํ๋ ํน์ ์ ๋ ฅ์ด ์ฃผ์ด์ง๊ณ ๋ค์ํ ์กฐ๊ฑด ํ์์ ๊ฐ ๋จ์๊ฐ ์์๋๋ก ์๋ํ๋์ง ํ์ธํ๋ ๊ฒ์ ๋๋ค. ํ๋ก ํธ์๋ ๊ฐ๋ฐ์ ๋งฅ๋ฝ์์ ๋จ์ ํ ์คํธ๋ ์ผ๋ฐ์ ์ผ๋ก ๊ฐ๋ณ ์ปดํฌ๋ํธ์ ๋ก์ง๊ณผ ๋์์ ํ ์คํธํ์ฌ ์ฌ๋ฐ๋ฅด๊ฒ ๋ ๋๋ง๋๊ณ ์ฌ์ฉ์ ์ํธ์์ฉ์ ์ ์ ํ๊ฒ ๋ฐ์ํ๋์ง ํ์ธํ๋ ๋ฐ ์ค์ ์ ๋ก๋๋ค.
๋จ์ ํ ์คํธ์ ์ด์
- ์กฐ๊ธฐ ๋ฒ๊ทธ ๋ฐ๊ฒฌ: ๋จ์ ํ ์คํธ๋ ๋ฒ๊ทธ๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ๋ถ๋ถ์ผ๋ก ํผ์ง๊ธฐ ์ ์ ๊ฐ๋ฐ ์ฃผ๊ธฐ ์ด๊ธฐ์ ๋ฒ๊ทธ๋ฅผ ๋ฐ๊ฒฌํ ์ ์์ต๋๋ค.
- ์ฝ๋ ํ์ง ํฅ์: ๋จ์ ํ ์คํธ๋ฅผ ์์ฑํ๋ฉด ๊ฐ๋ฐ์๊ฐ ๋ ๊นจ๋ํ๊ณ , ๋ชจ๋ํ๋๊ณ , ํ ์คํธํ๊ธฐ ์ฌ์ด ์ฝ๋๋ฅผ ์์ฑํ๋๋ก ์ฅ๋ คํฉ๋๋ค.
- ๋น ๋ฅธ ํผ๋๋ฐฑ ๋ฃจํ: ๋จ์ ํ ์คํธ๋ ์ผ๋ฐ์ ์ผ๋ก ์คํ ์๋๊ฐ ๋นจ๋ผ ๊ฐ๋ฐ์์๊ฒ ์ฝ๋ ๋ณ๊ฒฝ์ ๋ํ ์ ์ํ ํผ๋๋ฐฑ์ ์ ๊ณตํฉ๋๋ค.
- ๋๋ฒ๊น ์๊ฐ ๋จ์ถ: ๋ฒ๊ทธ๊ฐ ๋ฐ๊ฒฌ๋์์ ๋ ๋จ์ ํ ์คํธ๋ ๋ฌธ์ ์ ์ ํํ ์์น๋ฅผ ํ์ ํ๋ ๋ฐ ๋์์ ์ฃผ์ด ๋๋ฒ๊น ์๊ฐ์ ์ค์ฌ์ค๋๋ค.
- ์ฝ๋ ๋ณ๊ฒฝ์ ๋ํ ์์ ๊ฐ ์ฆ๊ฐ: ๋จ์ ํ ์คํธ๋ ์์ ๋ง์ ์ ๊ณตํ์ฌ ๊ฐ๋ฐ์๊ฐ ๊ธฐ์กด ๊ธฐ๋ฅ์ด ์์๋์ง ์์ ๊ฒ์ด๋ผ๋ ํ์ ์ ๊ฐ์ง๊ณ ์ฝ๋๋ฒ ์ด์ค๋ฅผ ๋ณ๊ฒฝํ ์ ์๊ฒ ํฉ๋๋ค.
- ๋ฌธ์ํ: ๋จ์ ํ ์คํธ๋ ๊ฐ ๋จ์๊ฐ ์ด๋ป๊ฒ ์ฌ์ฉ๋์ด์ผ ํ๋์ง๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ฝ๋์ ๋ฌธ์ ์ญํ ์ ํ ์ ์์ต๋๋ค.
๋จ์ ํ ์คํธ๋ฅผ ์ํ ๋๊ตฌ ๋ฐ ํ๋ ์์ํฌ
ํ๋ก ํธ์๋ ์ฝ๋์ ๋จ์ ํ ์คํธ๋ฅผ ์ํด ๋ค์๊ณผ ๊ฐ์ ์ฌ๋ฌ ์ธ๊ธฐ ์๋ ๋๊ตฌ์ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค:
- Jest: ํ์ด์ค๋ถ์์ ๊ฐ๋ฐํ ๋๋ฆฌ ์ฌ์ฉ๋๋ ์๋ฐ์คํฌ๋ฆฝํธ ํ ์คํธ ํ๋ ์์ํฌ๋ก, ๋จ์์ฑ, ์๋, ๊ทธ๋ฆฌ๊ณ ๋ชจํน(mocking) ๋ฐ ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง์ ๊ฐ์ ๋ด์ฅ ๊ธฐ๋ฅ์ผ๋ก ์ ๋ช ํฉ๋๋ค. Jest๋ ํนํ ๋ฆฌ์กํธ ์ํ๊ณ์์ ์ธ๊ธฐ๊ฐ ๋ง์ต๋๋ค.
- Mocha: ๊ฐ๋ฐ์๊ฐ ์ง์ ๋จ์ธ(assertion) ๋ผ์ด๋ธ๋ฌ๋ฆฌ(์: Chai)์ ๋ชจํน ๋ผ์ด๋ธ๋ฌ๋ฆฌ(์: Sinon.JS)๋ฅผ ์ ํํ ์ ์๋ ์ ์ฐํ๊ณ ํ์ฅ ๊ฐ๋ฅํ ์๋ฐ์คํฌ๋ฆฝํธ ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค.
- Jasmine: ๊น๋ํ ๊ตฌ๋ฌธ๊ณผ ํฌ๊ด์ ์ธ ๊ธฐ๋ฅ ์ธํธ๋ก ์๋ ค์ง ์๋ฐ์คํฌ๋ฆฝํธ์ฉ ํ๋ ์ฃผ๋ ๊ฐ๋ฐ(BDD) ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค.
- Karma: ์ฌ๋ฌ ๋ธ๋ผ์ฐ์ ์์ ํ ์คํธ๋ฅผ ์คํํ ์ ์๊ฒ ํด์ฃผ๋ ํ ์คํธ ๋ฌ๋๋ก, ํฌ๋ก์ค ๋ธ๋ผ์ฐ์ ํธํ์ฑ ํ ์คํธ๋ฅผ ์ ๊ณตํฉ๋๋ค.
ํจ๊ณผ์ ์ธ ๋จ์ ํ ์คํธ ์์ฑ๋ฒ
ํจ๊ณผ์ ์ธ ๋จ์ ํ ์คํธ๋ฅผ ์์ฑํ๊ธฐ ์ํ ๋ช ๊ฐ์ง ๋ชจ๋ฒ ์ฌ๋ก๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ํ ๋ฒ์ ํ ๊ฐ์ง๋ง ํ ์คํธํ๊ธฐ: ๊ฐ ๋จ์ ํ ์คํธ๋ ๋จ์ ๊ธฐ๋ฅ์ ๋จ์ผ ์ธก๋ฉด์ ํ ์คํธํ๋ ๋ฐ ์ง์คํด์ผ ํฉ๋๋ค.
- ์์ ์ ์ธ ํ ์คํธ ์ด๋ฆ ์ฌ์ฉํ๊ธฐ: ํ ์คํธ ์ด๋ฆ์ ๋ฌด์์ ํ ์คํธํ๋์ง ๋ช ํํ๊ฒ ์ค๋ช ํด์ผ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, "๋ ์ซ์์ ์ ํํ ํฉ๊ณ๋ฅผ ๋ฐํํด์ผ ํ๋ค"๋ ์ข์ ํ ์คํธ ์ด๋ฆ์ ๋๋ค.
- ๋ ๋ฆฝ์ ์ธ ํ ์คํธ ์์ฑํ๊ธฐ: ๊ฐ ํ ์คํธ๋ ๋ค๋ฅธ ํ ์คํธ์ ๋ ๋ฆฝ์ ์ด์ด์ผ ํ๋ฏ๋ก, ์คํ ์์๊ฐ ๊ฒฐ๊ณผ์ ์ํฅ์ ๋ฏธ์น์ง ์์์ผ ํฉ๋๋ค.
- ์์ ๋์์ ๊ฒ์ฆํ๊ธฐ ์ํด ๋จ์ธ ์ฌ์ฉํ๊ธฐ: ๋จ์ธ์ ์ฌ์ฉํ์ฌ ๋จ์์ ์ค์ ์ถ๋ ฅ์ด ์์ ์ถ๋ ฅ๊ณผ ์ผ์นํ๋์ง ํ์ธํฉ๋๋ค.
- ์ธ๋ถ ์์กด์ฑ ๋ชจํนํ๊ธฐ: ๋ชจํน์ ์ฌ์ฉํ์ฌ ํ ์คํธ ๋์ ๋จ์๋ฅผ API ํธ์ถ์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํธ์์ฉ๊ณผ ๊ฐ์ ์ธ๋ถ ์์กด์ฑ์ผ๋ก๋ถํฐ ๊ฒฉ๋ฆฌํฉ๋๋ค.
- ์ฝ๋๋ณด๋ค ๋จผ์ ํ ์คํธ ์์ฑํ๊ธฐ (ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ): ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ ์ ํ ์คํธ๋ฅผ ์์ฑํ๋ ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ(TDD) ์ ๊ทผ ๋ฐฉ์์ ์ฑํํ๋ ๊ฒ์ ๊ณ ๋ คํด ๋ณด์ธ์. ์ด๋ ๋ ๋์ ์ฝ๋๋ฅผ ์ค๊ณํ๊ณ ์ฝ๋๊ฐ ํ ์คํธ ๊ฐ๋ฅํ์ง ํ์ธํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
์์ : Jest๋ฅผ ์ฌ์ฉํ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ ๋จ์ ํ ์คํธ
์นด์ดํธ๋ฅผ ํ์ํ๊ณ ์ฌ์ฉ์๊ฐ ์ฆ๊ฐ ๋๋ ๊ฐ์์ํฌ ์ ์๋ `Counter`๋ผ๋ ๊ฐ๋จํ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๊ฐ ์๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค:
// Counter.js
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
const decrement = () => {
setCount(count - 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}
export default Counter;
๋ค์์ Jest๋ฅผ ์ฌ์ฉํ์ฌ ์ด ์ปดํฌ๋ํธ์ ๋ํ ๋จ์ ํ ์คํธ๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ๋๋ค:
// Counter.test.js
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import Counter from './Counter';
describe('Counter Component', () => {
it('should render the initial count correctly', () => {
const { getByText } = render(<Counter />);
expect(getByText('Count: 0')).toBeInTheDocument();
});
it('should increment the count when the increment button is clicked', () => {
const { getByText } = render(<Counter />);
const incrementButton = getByText('Increment');
fireEvent.click(incrementButton);
expect(getByText('Count: 1')).toBeInTheDocument();
});
it('should decrement the count when the decrement button is clicked', () => {
const { getByText } = render(<Counter />);
const decrementButton = getByText('Decrement');
fireEvent.click(decrementButton);
expect(getByText('Count: -1')).toBeInTheDocument();
});
});
์ด ์์ ๋ Jest์ `@testing-library/react`๋ฅผ ์ฌ์ฉํ์ฌ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๊ณ , ํด๋น ์์์ ์ํธ์์ฉํ๋ฉฐ, ์ปดํฌ๋ํธ๊ฐ ์์๋๋ก ์๋ํ๋์ง ๋จ์ธํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
ํตํฉ ํ ์คํธ: ๊ฐ๊ทน ๋ฉ์ฐ๊ธฐ
ํตํฉ ํ ์คํธ๋ ๋ฌด์์ธ๊ฐ?
ํตํฉ ํ ์คํธ๋ ์ปดํฌ๋ํธ, ๋ชจ๋ ๋๋ ์๋น์ค์ ๊ฐ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ๋ฌ ๋ถ๋ถ ๊ฐ์ ์ํธ์์ฉ์ ๊ฒ์ฆํ๋ ๋ฐ ์ค์ ์ ๋ก๋๋ค. ๋ชฉํ๋ ์ด๋ฌํ ์ฌ๋ฌ ๋ถ๋ถ์ด ํจ๊ป ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๊ณ ๋ฐ์ดํฐ๊ฐ ๊ทธ๋ค ์ฌ์ด์์ ์ํํ๊ฒ ํ๋ฅด๋์ง ํ์ธํ๋ ๊ฒ์ ๋๋ค. ํ๋ก ํธ์๋ ๊ฐ๋ฐ์์ ํตํฉ ํ ์คํธ๋ ์ผ๋ฐ์ ์ผ๋ก ์ปดํฌ๋ํธ ๊ฐ์ ์ํธ์์ฉ, ํ๋ก ํธ์๋์ ๋ฐฑ์๋ API ๊ฐ์ ์ํธ์์ฉ, ๋๋ ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์ ๋ด์ ๋ค๋ฅธ ๋ชจ๋ ๊ฐ์ ์ํธ์์ฉ์ ํ ์คํธํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค.
ํตํฉ ํ ์คํธ์ ์ด์
- ์ปดํฌ๋ํธ ์ํธ์์ฉ ๊ฒ์ฆ: ํตํฉ ํ ์คํธ๋ ์ปดํฌ๋ํธ๋ค์ด ์์๋๋ก ํจ๊ป ์๋ํ๋์ง ํ์ธํ์ฌ, ์๋ชป๋ ๋ฐ์ดํฐ ์ ๋ฌ์ด๋ ํต์ ํ๋กํ ์ฝ๋ก ์ธํด ๋ฐ์ํ ์ ์๋ ๋ฌธ์ ๋ฅผ ์ก์๋ ๋๋ค.
- ์ธํฐํ์ด์ค ์ค๋ฅ ์๋ณ: ํตํฉ ํ ์คํธ๋ ์๋ชป๋ API ์๋ํฌ์ธํธ๋ ๋ฐ์ดํฐ ํ์๊ณผ ๊ฐ์ ์์คํ ์ ์ฌ๋ฌ ๋ถ๋ถ ๊ฐ ์ธํฐํ์ด์ค ์ค๋ฅ๋ฅผ ์๋ณํ ์ ์์ต๋๋ค.
- ๋ฐ์ดํฐ ํ๋ฆ ๊ฒ์ฆ: ํตํฉ ํ ์คํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ๋ฌ ๋ถ๋ถ ๊ฐ์ ๋ฐ์ดํฐ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ํ๋ฅด๋์ง ๊ฒ์ฆํ์ฌ, ๋ฐ์ดํฐ๊ฐ ์์๋๋ก ๋ณํ๋๊ณ ์ฒ๋ฆฌ๋๋์ง ํ์ธํฉ๋๋ค.
- ์์คํ ์์ค ์คํจ ์ํ ๊ฐ์: ๊ฐ๋ฐ ์ฃผ๊ธฐ ์ด๊ธฐ์ ํตํฉ ๋ฌธ์ ๋ฅผ ์๋ณํ๊ณ ์์ ํจ์ผ๋ก์จ, ํ๋ก๋์ ํ๊ฒฝ์์ ์์คํ ์์ค์ ์คํจ ์ํ์ ์ค์ผ ์ ์์ต๋๋ค.
ํตํฉ ํ ์คํธ๋ฅผ ์ํ ๋๊ตฌ ๋ฐ ํ๋ ์์ํฌ
ํ๋ก ํธ์๋ ์ฝ๋์ ํตํฉ ํ ์คํธ์๋ ๋ค์๊ณผ ๊ฐ์ ์ฌ๋ฌ ๋๊ตฌ์ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค:
- React Testing Library: ์ข ์ข ๋ฆฌ์กํธ ์ปดํฌ๋ํธ์ ๋จ์ ํ ์คํธ์ ์ฌ์ฉ๋์ง๋ง, React Testing Library๋ ํตํฉ ํ ์คํธ์๋ ๋งค์ฐ ์ ํฉํ์ฌ ์ปดํฌ๋ํธ๊ฐ ์๋ก ๋ฐ DOM๊ณผ ์ด๋ป๊ฒ ์ํธ์์ฉํ๋์ง ํ ์คํธํ ์ ์์ต๋๋ค.
- Vue Test Utils: ์ปดํฌ๋ํธ ๋ง์ดํธ, ์์์์ ์ํธ์์ฉ, ๋์ ๋จ์ธ ๊ธฐ๋ฅ์ ํฌํจํ์ฌ Vue.js ์ปดํฌ๋ํธ ํ ์คํธ๋ฅผ ์ํ ์ ํธ๋ฆฌํฐ๋ฅผ ์ ๊ณตํฉ๋๋ค.
- Cypress: ํ๋ก ํธ์๋์ ๋ฐฑ์๋ API ๊ฐ์ ์ํธ์์ฉ์ ํ ์คํธํ ์ ์์ด ํตํฉ ํ ์คํธ์๋ ์ฌ์ฉํ ์ ์๋ ๊ฐ๋ ฅํ ์๋ํฌ์๋ ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค.
- Supertest: HTTP ์์ฒญ ํ ์คํธ๋ฅผ ์ํ ๊ณ ์์ค ์ถ์ํ๋ก, API ์๋ํฌ์ธํธ๋ฅผ ํ ์คํธํ๊ธฐ ์ํด Mocha๋ Jest์ ๊ฐ์ ํ ์คํธ ํ๋ ์์ํฌ์ ํจ๊ป ์์ฃผ ์ฌ์ฉ๋ฉ๋๋ค.
ํจ๊ณผ์ ์ธ ํตํฉ ํ ์คํธ ์์ฑ๋ฒ
ํจ๊ณผ์ ์ธ ํตํฉ ํ ์คํธ๋ฅผ ์์ฑํ๊ธฐ ์ํ ๋ช ๊ฐ์ง ๋ชจ๋ฒ ์ฌ๋ก๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ํธ์์ฉ์ ์ง์คํ๊ธฐ: ํตํฉ ํ ์คํธ๋ ๊ฐ๋ณ ๋จ์์ ๋ด๋ถ ๊ตฌํ ์ธ๋ถ ์ฌํญ์ ํ ์คํธํ๊ธฐ๋ณด๋ค๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ๋ฌ ๋ถ๋ถ ๊ฐ์ ์ํธ์์ฉ์ ํ ์คํธํ๋ ๋ฐ ์ง์คํด์ผ ํฉ๋๋ค.
- ํ์ค์ ์ธ ๋ฐ์ดํฐ ์ฌ์ฉํ๊ธฐ: ํตํฉ ํ ์คํธ์์ ์ค์ ์ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ค์ ์๋๋ฆฌ์ค๋ฅผ ์๋ฎฌ๋ ์ด์ ํ๊ณ ์ ์ฌ์ ์ธ ๋ฐ์ดํฐ ๊ด๋ จ ๋ฌธ์ ๋ฅผ ๋ฐ๊ฒฌํฉ๋๋ค.
- ์ธ๋ถ ์์กด์ฑ ๋ชจํน์ ๋๋ฌผ๊ฒ ์ฌ์ฉํ๊ธฐ: ๋ชจํน์ ๋จ์ ํ ์คํธ์ ํ์์ ์ด์ง๋ง, ํตํฉ ํ ์คํธ์์๋ ๋๋ฌผ๊ฒ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ๊ฐ๋ฅํ ํ ์ปดํฌ๋ํธ์ ์๋น์ค ๊ฐ์ ์ค์ ์ํธ์์ฉ์ ํ ์คํธํ๋๋ก ๋ ธ๋ ฅํ์ธ์.
- ์ฃผ์ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ๋ค๋ฃจ๋ ํ ์คํธ ์์ฑํ๊ธฐ: ์ ํ๋ฆฌ์ผ์ด์ ์์ ๊ฐ์ฅ ์ค์ํ ์ฌ์ฉ ์ฌ๋ก์ ์ํฌํ๋ก์ฐ๋ฅผ ๋ค๋ฃจ๋ ํตํฉ ํ ์คํธ ์์ฑ์ ์ง์คํ์ธ์.
- ํ ์คํธ ํ๊ฒฝ ์ฌ์ฉํ๊ธฐ: ๊ฐ๋ฐ ๋ฐ ํ๋ก๋์ ํ๊ฒฝ๊ณผ ๋ถ๋ฆฌ๋, ํตํฉ ํ ์คํธ ์ ์ฉ ํ ์คํธ ํ๊ฒฝ์ ์ฌ์ฉํ์ธ์. ์ด๋ ํ ์คํธ๊ฐ ๊ฒฉ๋ฆฌ๋๊ณ ๋ค๋ฅธ ํ๊ฒฝ์ ์ํฅ์ ์ฃผ์ง ์๋๋ก ๋ณด์ฅํฉ๋๋ค.
์์ : ๋ฆฌ์กํธ ์ปดํฌ๋ํธ ์ํธ์์ฉ ํตํฉ ํ ์คํธ
`ProductList`์ `ProductDetails`๋ผ๋ ๋ ๊ฐ์ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๊ฐ ์๋ค๊ณ ๊ฐ์ ํด ๋ด ์๋ค. `ProductList`๋ ์ ํ ๋ชฉ๋ก์ ํ์ํ๊ณ , ์ฌ์ฉ์๊ฐ ์ ํ์ ํด๋ฆญํ๋ฉด `ProductDetails`๊ฐ ํด๋น ์ ํ์ ์ธ๋ถ ์ ๋ณด๋ฅผ ํ์ํฉ๋๋ค.
// ProductList.js
import React, { useState } from 'react';
import ProductDetails from './ProductDetails';
function ProductList({ products }) {
const [selectedProduct, setSelectedProduct] = useState(null);
const handleProductClick = (product) => {
setSelectedProduct(product);
};
return (
<div>
<ul>
{products.map((product) => (
<li key={product.id} onClick={() => handleProductClick(product)}>
{product.name}
</li>
))}
</ul>
{selectedProduct && <ProductDetails product={selectedProduct} />}
</div>
);
}
export default ProductList;
// ProductDetails.js
import React from 'react';
function ProductDetails({ product }) {
return (
<div>
<h2>{product.name}</h2>
<p>{product.description}</p>
<p>Price: {product.price}</p>
</div>
);
}
export default ProductDetails;
๋ค์์ React Testing Library๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ค ์ปดํฌ๋ํธ์ ๋ํ ํตํฉ ํ ์คํธ๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ๋๋ค:
// ProductList.test.js
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import ProductList from './ProductList';
const products = [
{ id: 1, name: 'Product A', description: 'Description A', price: 10 },
{ id: 2, name: 'Product B', description: 'Description B', price: 20 },
];
describe('ProductList Component', () => {
it('should display product details when a product is clicked', () => {
const { getByText } = render(<ProductList products={products} />);
const productA = getByText('Product A');
fireEvent.click(productA);
expect(getByText('Description A')).toBeInTheDocument();
});
});
์ด ์์ ๋ React Testing Library๋ฅผ ์ฌ์ฉํ์ฌ `ProductList` ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๊ณ , ์ฌ์ฉ์์ ์ ํ ํด๋ฆญ์ ์๋ฎฌ๋ ์ด์ ํ๋ฉฐ, `ProductDetails` ์ปดํฌ๋ํธ๊ฐ ์ฌ๋ฐ๋ฅธ ์ ํ ์ ๋ณด์ ํจ๊ป ํ์๋๋์ง ๋จ์ธํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
์๋ํฌ์๋(E2E) ํ ์คํธ: ์ฌ์ฉ์ ๊ด์
E2E ํ ์คํธ๋ ๋ฌด์์ธ๊ฐ?
์๋ํฌ์๋(E2E) ํ ์คํธ๋ ์ค์ ์ฌ์ฉ์ ์ํธ์์ฉ์ ์๋ฎฌ๋ ์ด์ ํ์ฌ ์ฒ์๋ถํฐ ๋๊น์ง ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ํ๋ฆ์ ํ ์คํธํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค. ๋ชฉํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ชจ๋ ๋ถ๋ถ์ด ํจ๊ป ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ฌ์ฉ์์ ๊ธฐ๋๋ฅผ ์ถฉ์กฑํ๋์ง ํ์ธํ๋ ๊ฒ์ ๋๋ค. E2E ํ ์คํธ๋ ์ผ๋ฐ์ ์ผ๋ก ๋ค๋ฅธ ํ์ด์ง๋ก ์ด๋, ์์ ์์ฑ, ๋ฒํผ ํด๋ฆญ๊ณผ ๊ฐ์ ๋ธ๋ผ์ฐ์ ์ํธ์์ฉ์ ์๋ํํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์์๋๋ก ์๋ตํ๋์ง ๊ฒ์ฆํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค. E2E ํ ์คํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ํ์ค์ ์ธ ํ๊ฒฝ์์ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํ๊ธฐ ์ํด ์ข ์ข ์คํ ์ด์ง ๋๋ ํ๋ก๋์ ๊ณผ ์ ์ฌํ ํ๊ฒฝ์์ ์ํ๋ฉ๋๋ค.
E2E ํ ์คํธ์ ์ด์
- ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ํ๋ฆ ๊ฒ์ฆ: E2E ํ ์คํธ๋ ์ฌ์ฉ์์ ์ด๊ธฐ ์ํธ์์ฉ๋ถํฐ ์ต์ข ๊ฒฐ๊ณผ๊น์ง ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ํ๋ฆ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํฉ๋๋ค.
- ์์คํ ์์ค ๋ฒ๊ทธ ๋ฐ๊ฒฌ: E2E ํ ์คํธ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ, ๋คํธ์ํฌ ์ง์ฐ ๋๋ ๋ธ๋ผ์ฐ์ ํธํ์ฑ ๋ฌธ์ ์ ๊ฐ์ด ๋จ์ ๋๋ ํตํฉ ํ ์คํธ๋ก๋ ๋ฐ๊ฒฌ๋์ง ์์ ์ ์๋ ์์คํ ์์ค์ ๋ฒ๊ทธ๋ฅผ ๋ฐ๊ฒฌํ ์ ์์ต๋๋ค.
- ์ฌ์ฉ์ ๊ฒฝํ ๊ฒ์ฆ: E2E ํ ์คํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ํํ๊ณ ์ง๊ด์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ๋์ง ๊ฒ์ฆํ์ฌ ์ฌ์ฉ์๊ฐ ์์ ์ ๋ชฉํ๋ฅผ ์ฝ๊ฒ ๋ฌ์ฑํ ์ ์๋๋ก ๋ณด์ฅํฉ๋๋ค.
- ํ๋ก๋์ ๋ฐฐํฌ์ ๋ํ ์ ๋ขฐ๋ ์ ๊ณต: E2E ํ ์คํธ๋ ํ๋ก๋์ ๋ฐฐํฌ์ ๋ํ ๋์ ์์ค์ ์ ๋ขฐ๋ฅผ ์ ๊ณตํ์ฌ, ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ฌ์ฉ์์๊ฒ ๋ฆด๋ฆฌ์ค๋๊ธฐ ์ ์ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํฉ๋๋ค.
E2E ํ ์คํธ๋ฅผ ์ํ ๋๊ตฌ ๋ฐ ํ๋ ์์ํฌ
ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ E2E ํ ์คํธ๋ฅผ ์ํด ๋ค์๊ณผ ๊ฐ์ ์ฌ๋ฌ ๊ฐ๋ ฅํ ๋๊ตฌ์ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค:
- Cypress: ์ฌ์ฉ ํธ์์ฑ, ํฌ๊ด์ ์ธ ๊ธฐ๋ฅ ์ธํธ, ๋ฐ์ด๋ ๊ฐ๋ฐ์ ๊ฒฝํ์ผ๋ก ์ ๋ช ํ ์ธ๊ธฐ ์๋ E2E ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค. Cypress๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ๋ก ํ ์คํธ๋ฅผ ์์ฑํ ์ ์์ผ๋ฉฐ, ์๊ฐ ์ฌํ ๋๋ฒ๊น , ์๋ ๋๊ธฐ, ์ค์๊ฐ ๋ฆฌ๋ก๋์ ๊ฐ์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- Selenium WebDriver: ์ฌ๋ฌ ๋ธ๋ผ์ฐ์ ์ ์ด์ ์ฒด์ ์์ ๋ธ๋ผ์ฐ์ ์ํธ์์ฉ์ ์๋ํํ ์ ์๋ ๋๋ฆฌ ์ฌ์ฉ๋๋ E2E ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค. Selenium WebDriver๋ ์ข ์ข JUnit์ด๋ TestNG์ ๊ฐ์ ํ ์คํธ ํ๋ ์์ํฌ์ ํจ๊ป ์ฌ์ฉ๋ฉ๋๋ค.
- Playwright: ๋น ๋ฅด๊ณ ์์ ์ ์ด๋ฉฐ ํฌ๋ก์ค ๋ธ๋ผ์ฐ์ ํ ์คํธ๋ฅผ ์ ๊ณตํ๋๋ก ์ค๊ณ๋, ๋ง์ดํฌ๋ก์ํํธ์์ ๊ฐ๋ฐํ ๋น๊ต์ ์๋ก์ด E2E ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค. Playwright๋ ์๋ฐ์คํฌ๋ฆฝํธ, ํ์ ์คํฌ๋ฆฝํธ, ํ์ด์ฌ, ์๋ฐ๋ฅผ ํฌํจํ ์ฌ๋ฌ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ฅผ ์ง์ํฉ๋๋ค.
- Puppeteer: ๊ตฌ๊ธ์์ ๊ฐ๋ฐํ Node ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, ํค๋๋ฆฌ์ค ํฌ๋กฌ ๋๋ ํฌ๋ก๋ฏธ์์ ์ ์ดํ๊ธฐ ์ํ ๊ณ ์์ค API๋ฅผ ์ ๊ณตํฉ๋๋ค. Puppeteer๋ E2E ํ ์คํธ๋ฟ๋ง ์๋๋ผ ์น ์คํฌ๋ํ ๋ฐ ์๋ ์์ ์์ฑ๊ณผ ๊ฐ์ ๋ค๋ฅธ ์์ ์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํจ๊ณผ์ ์ธ E2E ํ ์คํธ ์์ฑ๋ฒ
ํจ๊ณผ์ ์ธ E2E ํ ์คํธ๋ฅผ ์์ฑํ๊ธฐ ์ํ ๋ช ๊ฐ์ง ๋ชจ๋ฒ ์ฌ๋ก๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ฃผ์ ์ฌ์ฉ์ ํ๋ฆ์ ์ง์คํ๊ธฐ: E2E ํ ์คํธ๋ ์ฌ์ฉ์ ๋ฑ๋ก, ๋ก๊ทธ์ธ, ๊ฒฐ์ ๋๋ ์์ ์ ์ถ๊ณผ ๊ฐ์ด ์ ํ๋ฆฌ์ผ์ด์ ์์ ๊ฐ์ฅ ์ค์ํ ์ฌ์ฉ์ ํ๋ฆ์ ํ ์คํธํ๋ ๋ฐ ์ง์คํด์ผ ํฉ๋๋ค.
- ํ์ค์ ์ธ ํ ์คํธ ๋ฐ์ดํฐ ์ฌ์ฉํ๊ธฐ: E2E ํ ์คํธ์์ ์ค์ ์ ๊ฐ์ ํ ์คํธ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ค์ ์๋๋ฆฌ์ค๋ฅผ ์๋ฎฌ๋ ์ด์ ํ๊ณ ์ ์ฌ์ ์ธ ๋ฐ์ดํฐ ๊ด๋ จ ๋ฌธ์ ๋ฅผ ๋ฐ๊ฒฌํฉ๋๋ค.
- ๊ฒฌ๊ณ ํ๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ ํ ์คํธ ์์ฑํ๊ธฐ: E2E ํ ์คํธ๋ ์ ์คํ๊ฒ ์์ฑํ์ง ์์ผ๋ฉด ๋ถ์์ ํ๊ณ ์คํจํ๊ธฐ ์ฝ์ต๋๋ค. ๋ช ํํ๊ณ ์์ ์ ์ธ ํ ์คํธ ์ด๋ฆ์ ์ฌ์ฉํ๊ณ , ์์ฃผ ๋ณ๊ฒฝ๋ ์ ์๋ ํน์ UI ์์์ ์์กดํ๋ ๊ฒ์ ํผํ๋ฉฐ, ๊ณตํต ํ ์คํธ ๋จ๊ณ๋ฅผ ์บก์ํํ๊ธฐ ์ํด ํฌํผ ํจ์๋ฅผ ์ฌ์ฉํ์ธ์.
- ์ผ๊ด๋ ํ๊ฒฝ์์ ํ ์คํธ ์คํํ๊ธฐ: ์ ์ฉ ์คํ ์ด์ง ๋๋ ํ๋ก๋์ ๊ณผ ์ ์ฌํ ํ๊ฒฝ๊ณผ ๊ฐ์ ์ผ๊ด๋ ํ๊ฒฝ์์ E2E ํ ์คํธ๋ฅผ ์คํํ์ธ์. ์ด๋ ํ ์คํธ๊ฐ ํ๊ฒฝ๋ณ ๋ฌธ์ ์ ์ํฅ์ ๋ฐ์ง ์๋๋ก ๋ณด์ฅํฉ๋๋ค.
- CI/CD ํ์ดํ๋ผ์ธ์ E2E ํ ์คํธ ํตํฉํ๊ธฐ: ์ฝ๋ ๋ณ๊ฒฝ์ด ์์ ๋๋ง๋ค ์๋์ผ๋ก ์คํ๋๋๋ก CI/CD ํ์ดํ๋ผ์ธ์ E2E ํ ์คํธ๋ฅผ ํตํฉํ์ธ์. ์ด๋ ๋ฒ๊ทธ๋ฅผ ์กฐ๊ธฐ์ ๋ฐ๊ฒฌํ๊ณ ํ๊ท๋ฅผ ๋ฐฉ์งํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
์์ : Cypress๋ฅผ ์ฌ์ฉํ E2E ํ ์คํธ
๋ค์๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ ๊ฐ์ง ๊ฐ๋จํ ํ ์ผ ๋ชฉ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ด ์๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค:
- ์ฌ์ฉ์๋ ๋ชฉ๋ก์ ์๋ก์ด ํ ์ผ ํญ๋ชฉ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
- ์ฌ์ฉ์๋ ํ ์ผ ํญ๋ชฉ์ ์๋ฃ๋ ๊ฒ์ผ๋ก ํ์ํ ์ ์์ต๋๋ค.
- ์ฌ์ฉ์๋ ๋ชฉ๋ก์์ ํ ์ผ ํญ๋ชฉ์ ์ญ์ ํ ์ ์์ต๋๋ค.
๋ค์์ Cypress๋ฅผ ์ฌ์ฉํ์ฌ ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ํ E2E ํ ์คํธ๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ๋๋ค:
// cypress/integration/todo.spec.js
describe('To-Do List Application', () => {
beforeEach(() => {
cy.visit('/'); // Assuming the application is running at the root URL
});
it('should add a new to-do item', () => {
cy.get('input[type="text"]').type('Buy groceries');
cy.get('button').contains('Add').click();
cy.get('li').should('contain', 'Buy groceries');
});
it('should mark a to-do item as completed', () => {
cy.get('li').contains('Buy groceries').find('input[type="checkbox"]').check();
cy.get('li').contains('Buy groceries').should('have.class', 'completed'); // Assuming completed items have a class named "completed"
});
it('should delete a to-do item', () => {
cy.get('li').contains('Buy groceries').find('button').contains('Delete').click();
cy.get('li').should('not.contain', 'Buy groceries');
});
});
์ด ์์ ๋ Cypress๋ฅผ ์ฌ์ฉํ์ฌ ๋ธ๋ผ์ฐ์ ์ํธ์์ฉ์ ์๋ํํ๊ณ ํ ์ผ ๋ชฉ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ด ์์๋๋ก ์๋ํ๋์ง ๊ฒ์ฆํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค. Cypress๋ DOM ์์์ ์ํธ์์ฉํ๊ณ , ๊ทธ ์์ฑ์ ๋จ์ธํ๋ฉฐ, ์ฌ์ฉ์ ํ๋์ ์๋ฎฌ๋ ์ด์ ํ๊ธฐ ์ํ ์ ์ฐฝํ API๋ฅผ ์ ๊ณตํฉ๋๋ค.
ํผ๋ผ๋ฏธ๋์ ๊ท ํ ๋ง์ถ๊ธฐ: ์ฌ๋ฐ๋ฅธ ์กฐํฉ ์ฐพ๊ธฐ
ํ ์คํธ ํผ๋ผ๋ฏธ๋๋ ์๊ฒฉํ ์ฒ๋ฐฉ์ด ์๋๋ผ ํ์ด ํ ์คํธ ๋ ธ๋ ฅ์ ์ฐ์ ์์๋ฅผ ์ ํ๋ ๋ฐ ๋์์ด ๋๋ ๊ฐ์ด๋๋ผ์ธ์ ๋๋ค. ๊ฐ ์ ํ์ ํ ์คํธ์ ์ ํํ ๋น์จ์ ํ๋ก์ ํธ์ ํน์ ์๊ตฌ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, ๋น์ฆ๋์ค ๋ก์ง์ด ๋ง์ ๋ณต์กํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ก์ง์ด ์ฒ ์ ํ ํ ์คํธ๋์๋์ง ํ์ธํ๊ธฐ ์ํด ๋ ๋์ ๋น์จ์ ๋จ์ ํ ์คํธ๊ฐ ํ์ํ ์ ์์ต๋๋ค. ์ฌ์ฉ์ ๊ฒฝํ์ ์ค์ ์ ๋ ๊ฐ๋จํ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉ์ ์ธํฐํ์ด์ค๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํ๊ธฐ ์ํด ๋ ๋์ ๋น์จ์ E2E ํ ์คํธ๋ก๋ถํฐ ์ด์ ์ ์ป์ ์ ์์ต๋๋ค.
๊ถ๊ทน์ ์ผ๋ก ๋ชฉํ๋ ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง, ํ ์คํธ ์๋ ๋ฐ ํ ์คํธ ์ ์ง๋ณด์์ฑ ์ฌ์ด์์ ์ต์์ ๊ท ํ์ ์ ๊ณตํ๋ ๋จ์, ํตํฉ, E2E ํ ์คํธ์ ์ฌ๋ฐ๋ฅธ ์กฐํฉ์ ์ฐพ๋ ๊ฒ์ ๋๋ค.
๊ณผ์ ๋ฐ ๊ณ ๋ ค์ฌํญ
๊ฒฌ๊ณ ํ ํ ์คํธ ์ ๋ต์ ๊ตฌํํ๋ ๋ฐ์๋ ๋ช ๊ฐ์ง ๊ณผ์ ๊ฐ ๋ฐ๋ฅผ ์ ์์ต๋๋ค:
- ํ ์คํธ ๋ถ์์ ์ฑ(Flakiness): ํนํ E2E ํ ์คํธ๋ ๋ถ์์ ํด์ง๊ธฐ ์ฌ์ด๋ฐ, ์ด๋ ๋คํธ์ํฌ ์ง์ฐ์ด๋ ํ์ด๋ฐ ๋ฌธ์ ์ ๊ฐ์ ์์ธ์ผ๋ก ์ธํด ๋ฌด์์๋ก ํต๊ณผํ๊ฑฐ๋ ์คํจํ ์ ์์์ ์๋ฏธํฉ๋๋ค. ํ ์คํธ ๋ถ์์ ์ฑ์ ํด๊ฒฐํ๋ ค๋ฉด ์ ์คํ ํ ์คํธ ์ค๊ณ, ๊ฒฌ๊ณ ํ ์ค๋ฅ ์ฒ๋ฆฌ, ๊ทธ๋ฆฌ๊ณ ์ ์ฌ์ ์ผ๋ก ์ฌ์๋ ๋ฉ์ปค๋์ฆ์ ์ฌ์ฉ์ด ํ์ํฉ๋๋ค.
- ํ ์คํธ ์ ์ง๋ณด์: ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ฐ์ ํจ์ ๋ฐ๋ผ ์ฝ๋๋ ์ฌ์ฉ์ ์ธํฐํ์ด์ค์ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฐ์ํ๊ธฐ ์ํด ํ ์คํธ๋ฅผ ์ ๋ฐ์ดํธํด์ผ ํ ์ ์์ต๋๋ค. ํ ์คํธ๋ฅผ ์ต์ ์ํ๋ก ์ ์งํ๋ ๊ฒ์ ์๊ฐ์ด ๋ง์ด ๊ฑธ๋ฆฌ๋ ์์ ์ผ ์ ์์ง๋ง, ํ ์คํธ๊ฐ ๊ด๋ จ์ฑ ์๊ณ ํจ๊ณผ์ ์ผ๋ก ์ ์ง๋๋๋ก ํ๋ ๋ฐ ํ์์ ์ ๋๋ค.
- ํ ์คํธ ํ๊ฒฝ ์ค์ : ์ผ๊ด๋ ํ ์คํธ ํ๊ฒฝ์ ์ค์ ํ๊ณ ์ ์งํ๋ ๊ฒ์ ์ด๋ ค์ธ ์ ์์ผ๋ฉฐ, ํนํ ์ ์ฒด ์คํ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์คํ๋์ด์ผ ํ๋ E2E ํ ์คํธ์ ๊ฒฝ์ฐ ๋์ฑ ๊ทธ๋ ์ต๋๋ค. ํ ์คํธ ํ๊ฒฝ ์ค์ ์ ๋จ์ํํ๊ธฐ ์ํด ๋์ปค(Docker)์ ๊ฐ์ ์ปจํ ์ด๋ํ ๊ธฐ์ ์ด๋ ํด๋ผ์ฐ๋ ๊ธฐ๋ฐ ํ ์คํธ ์๋น์ค๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ณ ๋ คํด ๋ณด์ธ์.
- ํ์ ๊ธฐ์ ์ญ๋: ํฌ๊ด์ ์ธ ํ ์คํธ ์ ๋ต์ ๊ตฌํํ๋ ค๋ฉด ๋ค์ํ ํ ์คํธ ๊ธฐ์ ๊ณผ ๋๊ตฌ์ ๋ํ ํ์ํ ๊ธฐ์ ๊ณผ ์ ๋ฌธ ์ง์์ ๊ฐ์ถ ํ์ด ํ์ํฉ๋๋ค. ํ์ด ํจ๊ณผ์ ์ธ ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ์ ์งํ๋ ๋ฐ ํ์ํ ๊ธฐ์ ์ ๊ฐ์ถ ์ ์๋๋ก ๊ต์ก๊ณผ ๋ฉํ ๋ง์ ํฌ์ํ์ธ์.
๊ฒฐ๋ก
ํ๋ก ํธ์๋ ํ ์คํธ ํผ๋ผ๋ฏธ๋๋ ํ ์คํธ ๋ ธ๋ ฅ์ ์ฒด๊ณํํ๊ณ ๊ฒฌ๊ณ ํ๋ฉฐ ์ ๋ขฐํ ์ ์๋ ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ์ ์ฉํ ํ๋ ์์ํฌ๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋จ์ ํ ์คํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๊ณ ํตํฉ ๋ฐ E2E ํ ์คํธ๋ก ๋ณด์ํจ์ผ๋ก์จ, ํฌ๊ด์ ์ธ ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ๋ฌ์ฑํ๊ณ ๊ฐ๋ฐ ์ฃผ๊ธฐ ์ด๊ธฐ์ ๋ฒ๊ทธ๋ฅผ ๋ฐ๊ฒฌํ ์ ์์ต๋๋ค. ํฌ๊ด์ ์ธ ํ ์คํธ ์ ๋ต์ ๊ตฌํํ๋ ๊ฒ์ด ์ด๋ ค์ธ ์ ์์ง๋ง, ์ฝ๋ ํ์ง ํฅ์, ๋๋ฒ๊น ์๊ฐ ๋จ์ถ, ํ๋ก๋์ ๋ฐฐํฌ์ ๋ํ ์์ ๊ฐ ์ฆ๊ฐ๋ผ๋ ์ด์ ์ ๋น์ฉ์ ํจ์ฌ ๋ฅ๊ฐํฉ๋๋ค. ํ ์คํธ ํผ๋ผ๋ฏธ๋๋ฅผ ์์ฉํ๊ณ ํ์ด ์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ๋ง์กฑ์ํค๋ ๊ณ ํ์ง ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ์ ์๋๋ก ์ญ๋์ ๊ฐํํ์ธ์. ํ๋ก์ ํธ์ ํน์ ์๊ตฌ์ ๋ง๊ฒ ํผ๋ผ๋ฏธ๋๋ฅผ ์กฐ์ ํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ฐ์ ํจ์ ๋ฐ๋ผ ํ ์คํธ ์ ๋ต์ ์ง์์ ์ผ๋ก ๊ฐ์ ํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค. ๊ฒฌ๊ณ ํ๊ณ ์ ๋ขฐํ ์ ์๋ ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ๊ฐ๋ ์ฌ์ ์ ํ ์คํธ ๊ดํ์ ๋ฐฐ์ฐ๊ณ , ์ ์ํ๊ณ , ๊ฐ์ ํ๋ ์ง์์ ์ธ ๊ณผ์ ์ ๋๋ค.