JavaScript ํ๋ก์ ํธ๋ฅผ ์ํ ๊ฒฌ๊ณ ํ ์ง์์ ํตํฉ(CI) ํ์ดํ๋ผ์ธ ์ค์ ๋ฐฉ๋ฒ์ ์ฌ์ธต ๋ถ์ํฉ๋๋ค. GitHub Actions, GitLab CI, Jenkins์ ๊ฐ์ ๊ธ๋ก๋ฒ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ ์๋ํ ํ ์คํธ์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐฐ์๋ณด์ธ์.
JavaScript ํ ์คํธ ์๋ํ: ์ง์์ ํตํฉ(CI) ์ค์ ์ ์ํ ์ข ํฉ ๊ฐ์ด๋
์ด๋ฐ ์๋๋ฆฌ์ค๋ฅผ ์์ํด ๋ณด์ธ์. ๋ฆ์ ๊ทผ๋ฌด ์๊ฐ, ๋น์ ์ ์ฌ์ํ ๋ฒ๊ทธ ์์ ์ด๋ผ๊ณ ์๊ฐํ ์ฝ๋๋ฅผ ๋ฉ์ธ ๋ธ๋์น์ ํธ์ํ์ต๋๋ค. ์ ์ ํ, ๊ฒฝ๊ณ ์๋ฆผ์ด ์ธ๋ฆฌ๊ธฐ ์์ํฉ๋๋ค. ๊ณ ๊ฐ ์ง์ ์ฑ๋์๋ ๊ด๋ จ ์๋ ํต์ฌ ๊ธฐ๋ฅ์ด ์์ ํ ๋ง๊ฐ์ก๋ค๋ ๋ณด๊ณ ๊ฐ ์๋ํฉ๋๋ค. ์คํธ๋ ์ค๊ฐ ์ฌํ๊ณ ์๋ฐ์ด ํฐ ํซํฝ์ค ์์ ์ด ๊ธด๊ธํ๊ฒ ์์๋ฉ๋๋ค. ์ ์ธ๊ณ ๊ฐ๋ฐํ์๊ฒ ๋๋ฌด๋ ํํ ์ด ์ํฉ์, ๋ฐ๋ก ๊ฒฌ๊ณ ํ ์๋ํ ํ ์คํธ์ ์ง์์ ํตํฉ(CI) ์ ๋ต์ด ๋ง๊ธฐ ์ํด ๊ณ ์๋ ๊ฒ์ ๋๋ค.
์ค๋๋ ๋น ๋ฅด๊ฒ ๋ณํํ๋ ๊ธ๋ก๋ฒ ์ํํธ์จ์ด ๊ฐ๋ฐ ํ๊ฒฝ์์ ์๋์ ํ์ง์ ์ํธ ๋ฐฐํ์ ์ธ ๊ฒ์ด ์๋๋ผ ์ํธ ์์กด์ ์ ๋๋ค. ์ ๋ขฐํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ์ํ๊ฒ ์ถ์ํ๋ ๋ฅ๋ ฅ์ ์๋นํ ๊ฒฝ์ ์ฐ์์ ๋๋ค. ๋ฐ๋ก ์ด ์ง์ ์์ ์๋ํ๋ JavaScript ํ ์คํธ์ ์ง์์ ํตํฉ ํ์ดํ๋ผ์ธ์ ์๋์ง๊ฐ ํ๋์ ์ธ ๊ณ ์ฑ๋ฅ ์์ง๋์ด๋ง ํ์ ์ด์์ด ๋ฉ๋๋ค. ์ด ๊ฐ์ด๋๋ ๊ฐ๋ฐ์, ํ ๋ฆฌ๋, DevOps ์์ง๋์ด ๋ฑ ์ ์ธ๊ณ ๋ ์๋ฅผ ๋์์ผ๋ก ๋ชจ๋ JavaScript ํ๋ก์ ํธ์ ๋ํ CI ์ค์ ์ ์ดํดํ๊ณ , ๊ตฌํํ๋ฉฐ, ์ต์ ํํ๊ธฐ ์ํ ํฌ๊ด์ ์ธ ๋ก๋๋งต ์ญํ ์ ํ ๊ฒ์ ๋๋ค.
'์?': CI์ ํต์ฌ ์์น ์ดํดํ๊ธฐ
์ค์ ํ์ผ๊ณผ ํน์ ๋๊ตฌ์ ๋ํด ์์๋ณด๊ธฐ ์ ์, ์ง์์ ํตํฉ ๋ค์ ์๋ ์ฒ ํ์ ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. CI๋ ๋จ์ํ ์๊ฒฉ ์๋ฒ์์ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๋ ๊ฒ์ด ์๋๋ผ, ํ์ด ํ์ ํ๊ณ ์ํํธ์จ์ด๋ฅผ ์ ๊ณตํ๋ ๋ฐฉ์์ ์ง๋ํ ์ํฅ์ ๋ฏธ์น๋ ๊ฐ๋ฐ ๊ดํ์ด์ ๋ฌธํ์ ๋ณํ์ ๋๋ค.
์ง์์ ํตํฉ(CI)์ด๋ ๋ฌด์์ธ๊ฐ?
์ง์์ ํตํฉ์ ๋ชจ๋ ๊ฐ๋ฐ์์ ์์ ์ฝ๋ ๋ณต์ฌ๋ณธ์ ๊ณต์ ๋ฉ์ธ๋ผ์ธ์ ์์ฃผ ๋ณํฉํ๋ ๊ดํ์ผ๋ก, ์ข ์ข ํ๋ฃจ์๋ ์ฌ๋ฌ ๋ฒ ์ด๋ฃจ์ด์ง๋๋ค. ๊ฐ ๋ณํฉ, ์ฆ 'ํตํฉ'์ ๋น๋์ ์ผ๋ จ์ ์๋ํ๋ ํ ์คํธ๋ฅผ ํตํด ์๋์ผ๋ก ๊ฒ์ฆ๋ฉ๋๋ค. ์ฃผ๋ ๋ชฉํ๋ ํตํฉ ๋ฒ๊ทธ๋ฅผ ๊ฐ๋ฅํ ํ ๋นจ๋ฆฌ ๋ฐ๊ฒฌํ๋ ๊ฒ์ ๋๋ค.
์๋ก์ด ์ฝ๋ ๊ธฐ์ฌ๊ฐ ๊ธฐ์กด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๊ฐ๋จ๋ฆฌ์ง ์๋์ง ๋์์์ด ํ์ธํ๋, ๊ฒฝ๊ณ์ฌ ๋ง๊ณ ์๋ํ๋ ํ์์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋ฉ๋๋ค. ์ด ์ฆ๊ฐ์ ์ธ ํผ๋๋ฐฑ ๋ฃจํ๋ CI์ ์ฌ์ฅ์ด์ ๊ฐ์ฅ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ๋๋ค.
CI ๋์ ์ ํต์ฌ ์ด์
- ์กฐ๊ธฐ ๋ฒ๊ทธ ๋ฐ๊ฒฌ ๋ฐ ๋น ๋ฅธ ํผ๋๋ฐฑ: ๋ชจ๋ ๋ณ๊ฒฝ ์ฌํญ์ ํ ์คํธํจ์ผ๋ก์จ ๋ฉฐ์น ์ด๋ ๋ช ์ฃผ๊ฐ ์๋ ๋ช ๋ถ ์์ ๋ฒ๊ทธ๋ฅผ ์ก์๋ ๋๋ค. ์ด๋ ๋ฒ๊ทธ ์์ ์ ํ์ํ ์๊ฐ๊ณผ ๋น์ฉ์ ๊ทน์ ์ผ๋ก ์ค์ฌ์ค๋๋ค. ๊ฐ๋ฐ์๋ ์์ ์ ๋ณ๊ฒฝ ์ฌํญ์ ๋ํด ์ฆ๊ฐ์ ์ธ ํผ๋๋ฐฑ์ ๋ฐ์ ๋น ๋ฅด๊ณ ์์ ๊ฐ ์๊ฒ ๋ฐ๋ณต ์์ ์ ์ํํ ์ ์์ต๋๋ค.
- ์ฝ๋ ํ์ง ํฅ์: CI ํ์ดํ๋ผ์ธ์ ํ์ง ๊ฒ์ดํธ ์ญํ ์ ํฉ๋๋ค. ๋ฆฐํฐ(linter)๋ก ์ฝ๋ฉ ํ์ค์ ๊ฐ์ ํ๊ณ , ํ์ ์ค๋ฅ๋ฅผ ํ์ธํ๋ฉฐ, ์๋ก์ด ์ฝ๋์ ํ ์คํธ๊ฐ ํฌํจ๋๋๋ก ๋ณด์ฅํ ์ ์์ต๋๋ค. ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ์ด๋ ์ ์ฒด ์ฝ๋๋ฒ ์ด์ค์ ํ์ง๊ณผ ์ ์ง๋ณด์์ฑ์ ์ฒด๊ณ์ ์ผ๋ก ๋์ ๋๋ค.
- ๋ณํฉ ์ถฉ๋ ๊ฐ์: ์์ ์ฝ๋ ๋ฌถ์์ ์์ฃผ ํตํฉํจ์ผ๋ก์จ ๊ฐ๋ฐ์๋ค์ ํฌ๊ณ ๋ณต์กํ ๋ณํฉ ์ถฉ๋('๋ณํฉ ์ง์ฅ')์ ์ง๋ฉดํ ๊ฐ๋ฅ์ฑ์ด ์ค์ด๋ญ๋๋ค. ์ด๋ ์๋นํ ์๊ฐ์ ์ ์ฝํ๊ณ ์๋ ๋ณํฉ ์ค ์ค๋ฅ ๋ฐ์ ์ํ์ ๊ฐ์์ํต๋๋ค.
- ๊ฐ๋ฐ์ ์์ฐ์ฑ ๋ฐ ์์ ๊ฐ ํฅ์: ์๋ํ๋ ๊ฐ๋ฐ์๋ฅผ ์ง๋ฃจํ ์๋ ํ ์คํธ ๋ฐ ๋ฐฐํฌ ํ๋ก์ธ์ค์์ ํด๋ฐฉ์ํต๋๋ค. ํฌ๊ด์ ์ธ ํ ์คํธ ์ค์ํธ๊ฐ ์ฝ๋๋ฒ ์ด์ค๋ฅผ ์งํค๊ณ ์๋ค๋ ์ฌ์ค์ ๊ฐ๋ฐ์๊ฐ ํ๊ท(regression) ๋ฐ์์ ๋ํ ๋๋ ค์ ์์ด ๋ฆฌํฉํ ๋ง, ํ์ , ๊ธฐ๋ฅ ์ถ์๋ฅผ ํ ์ ์๋ ์์ ๊ฐ์ ์ค๋๋ค.
- ๋จ์ผ ์ง์ค ๊ณต๊ธ์(A Single Source of Truth): CI ์๋ฒ๋ '๋ น์(์ฑ๊ณต)' ๋๋ '์ ์(์คํจ)' ๋น๋์ ๋ํ ์ต์ข ์ ์ธ ์ ๋ณด ์ถ์ฒ๊ฐ ๋ฉ๋๋ค. ์ง๋ฆฌ์ ์์น๋ ์๊ฐ๋์ ๊ด๊ณ์์ด ํ์ ๋ชจ๋ ๊ตฌ์ฑ์์ ์ธ์ ๋ ์ง ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ๋ฅผ ๋ช ํํ๊ฒ ํ์ ํ ์ ์์ต๋๋ค.
'๋ฌด์์?': JavaScript ํ ์คํธ์ ์ข ๋ฅ
์ฑ๊ณต์ ์ธ CI ํ์ดํ๋ผ์ธ์ ์คํํ๋ ํ ์คํธ์ ํ์ง์ ์ข์ฐ๋ฉ๋๋ค. ํ ์คํธ๋ฅผ ๊ตฌ์กฐํํ๋ ์ผ๋ฐ์ ์ด๊ณ ํจ๊ณผ์ ์ธ ์ ๋ต์ 'ํ ์คํ ํผ๋ผ๋ฏธ๋'์ ๋๋ค. ์ด๋ ๋ค์ํ ์ ํ์ ํ ์คํธ ๊ฐ์ ๊ฑด๊ฐํ ๊ท ํ์ ์๊ฐํํฉ๋๋ค.
ํผ๋ผ๋ฏธ๋๋ฅผ ์์ํด ๋ณด์ธ์:
- ๊ธฐ๋ฐ (๊ฐ์ฅ ๋์ ์์ญ): ์ ๋ ํ ์คํธ(Unit Tests). ๋น ๋ฅด๊ณ , ์๊ฐ ๋ง์ผ๋ฉฐ, ์ฝ๋์ ๊ฐ์ฅ ์์ ์กฐ๊ฐ์ ๊ฒฉ๋ฆฌํ์ฌ ํ์ธํฉ๋๋ค.
- ์ค๊ฐ: ํตํฉ ํ ์คํธ(Integration Tests). ์ฌ๋ฌ ์ ๋์ด ์์๋๋ก ํจ๊ป ์๋ํ๋์ง ๊ฒ์ฆํฉ๋๋ค.
- ์ ์ (๊ฐ์ฅ ์ข์ ์์ญ): ์๋ํฌ์๋(E2E) ํ ์คํธ. ์ค์ ์ฌ์ฉ์๊ฐ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉํ๋ ๊ณผ์ ์ ์๋ฎฌ๋ ์ด์ ํ๋, ๋ ๋๋ฆฌ๊ณ ๋ณต์กํ ํ ์คํธ์ ๋๋ค.
์ ๋ ํ ์คํธ: ๊ธฐ์ด
์ ๋ ํ ์คํธ๋ ๋จ์ผ ํจ์, ๋ฉ์๋ ๋๋ ์ปดํฌ๋ํธ์ ์ค์ ์ ๋ก๋๋ค. ์ข ์ข '๋ชฉ(mock)'์ด๋ '์คํ (stub)'์ ์ฌ์ฉํ์ฌ ์์กด์ฑ์ ์๋ฎฌ๋ ์ด์ ํ๋ฉฐ, ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋จธ์ง ๋ถ๋ถ๊ณผ ๊ฒฉ๋ฆฌ๋ฉ๋๋ค. ๋ชฉํ๋ ํน์ ๋ก์ง ์กฐ๊ฐ์ด ๋ค์ํ ์ ๋ ฅ์ ๋ํด ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํ๋ ๊ฒ์ ๋๋ค.
- ๋ชฉ์ : ๊ฐ๋ณ ๋ก์ง ์ ๋ ๊ฒ์ฆ.
- ์๋: ๋งค์ฐ ๋น ๋ฆ (ํ ์คํธ๋น ๋ฐ๋ฆฌ์ด).
- ์ฃผ์ ๋๊ตฌ:
- Jest: ๋ด์ฅ๋ ๋จ์ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ๋ชจ์(mocking) ๊ธฐ๋ฅ, ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง ๋๊ตฌ๋ฅผ ๊ฐ์ถ ์ธ๊ธฐ ์๋ ์ฌ์ธ์ ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค. Meta์์ ์ ์ง๋ณด์ํฉ๋๋ค.
- Vitest: Vite ๋น๋ ๋๊ตฌ์ ์ํํ๊ฒ ์๋ํ๋๋ก ์ค๊ณ๋ ํ๋์ ์ด๊ณ ๋งค์ฐ ๋น ๋ฅธ ํ ์คํธ ํ๋ ์์ํฌ๋ก, Jest์ ํธํ๋๋ API๋ฅผ ์ ๊ณตํฉ๋๋ค.
- Mocha: ํ ์คํธ์ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ ์ ๊ณตํ๋ ๋งค์ฐ ์ ์ฐํ๊ณ ์ฑ์ํ ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค. ์ข ์ข Chai์ ๊ฐ์ ๋จ์ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํจ๊ป ์ฌ์ฉ๋ฉ๋๋ค.
ํตํฉ ํ ์คํธ: ์ฐ๊ฒฐ ์กฐ์ง
ํตํฉ ํ ์คํธ๋ ์ ๋ ํ ์คํธ๋ณด๋ค ํ ๋จ๊ณ ๋ ๋์๊ฐ๋๋ค. ์ฌ๋ฌ ์ ๋์ด ์ด๋ป๊ฒ ํ๋ ฅํ๋์ง ํ์ธํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ ํตํฉ ํ ์คํธ๋ ์ฌ๋ฌ ์์ ์ปดํฌ๋ํธ๋ฅผ ํฌํจํ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๊ณ ์ฌ์ฉ์๊ฐ ๋ฒํผ์ ํด๋ฆญํ์ ๋ ์ฌ๋ฐ๋ฅด๊ฒ ์ํธ ์์ฉํ๋์ง ํ์ธํ ์ ์์ต๋๋ค.
- ๋ชฉ์ : ๋ชจ๋ ๋๋ ์ปดํฌ๋ํธ ๊ฐ์ ์ํธ ์์ฉ ๊ฒ์ฆ.
- ์๋: ์ ๋ ํ ์คํธ๋ณด๋ค ๋๋ฆฌ์ง๋ง E2E ํ ์คํธ๋ณด๋ค๋ ๋น ๋ฆ.
- ์ฃผ์ ๋๊ตฌ:
- React Testing Library: ํ ์คํธ ๋ฌ๋๋ ์๋์ง๋ง, ๊ตฌํ ์ธ๋ถ ์ฌํญ๋ณด๋ค๋ ์ ํ๋ฆฌ์ผ์ด์ ๋์์ ํ ์คํธํ๋๋ก ๊ถ์ฅํ๋ ์ ํธ๋ฆฌํฐ ์ธํธ์ ๋๋ค. Jest๋ Vitest์ ๊ฐ์ ๋ฌ๋์ ํจ๊ป ์๋ํฉ๋๋ค.
- Supertest: Node.js HTTP ์๋ฒ ํ ์คํธ์ ๋๋ฆฌ ์ฌ์ฉ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, API ํตํฉ ํ ์คํธ์ ํ์ํฉ๋๋ค.
์๋ํฌ์๋(E2E) ํ ์คํธ: ์ฌ์ฉ์ ๊ด์
E2E ํ ์คํธ๋ ์ค์ ๋ธ๋ผ์ฐ์ ๋ฅผ ์๋ํํ์ฌ ์์ ํ ์ฌ์ฉ์ ์ํฌํ๋ก์ฐ๋ฅผ ์๋ฎฌ๋ ์ด์ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์ ์ ์๊ฑฐ๋ ์ฌ์ดํธ์ E2E ํ ์คํธ๋ ํํ์ด์ง ๋ฐฉ๋ฌธ, ์ ํ ๊ฒ์, ์ฅ๋ฐ๊ตฌ๋์ ์ถ๊ฐ, ๊ฒฐ์ ํ์ด์ง๋ก ์ด๋ํ๋ ๊ณผ์ ์ ํฌํจํ ์ ์์ต๋๋ค. ์ด๋ฌํ ํ ์คํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฒด๊ฐ ์ ๋๋ก ์๋ํ๋ค๋ ๊ฐ์ฅ ๋์ ์์ค์ ํ์ ์ ์ ๊ณตํฉ๋๋ค.
- ๋ชฉ์ : ์ฒ์๋ถํฐ ๋๊น์ง ์์ ํ ์ฌ์ฉ์ ํ๋ฆ ๊ฒ์ฆ.
- ์๋: ๊ฐ์ฅ ๋๋ฆฌ๊ณ ๊นจ์ง๊ธฐ ์ฌ์ด ์ ํ์ ํ ์คํธ.
- ์ฃผ์ ๋๊ตฌ:
- Cypress: ๋ฐ์ด๋ ๊ฐ๋ฐ์ ๊ฒฝํ, ๋ํํ ํ ์คํธ ๋ฌ๋, ์ ๋ขฐ์ฑ์ผ๋ก ์๋ ค์ง ํ๋์ ์ธ ์ฌ์ธ์ E2E ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค.
- Playwright: Microsoft์์ ๋ง๋ ๊ฐ๋ ฅํ ํ๋ ์์ํฌ๋ก, ๋จ์ผ API๋ก ํฌ๋ก์ค ๋ธ๋ผ์ฐ์ ์๋ํ(Chromium, Firefox, WebKit)๋ฅผ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค. ์๋์ ๊ณ ๊ธ ๊ธฐ๋ฅ์ผ๋ก ์ ๋ช ํฉ๋๋ค.
- Selenium WebDriver: ๋ธ๋ผ์ฐ์ ์๋ํ์ ์ค๋ ํ์ค์ผ๋ก, ๋ฐฉ๋ํ ์ข ๋ฅ์ ์ธ์ด์ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ง์ํฉ๋๋ค. ์ต๋์ ์ ์ฐ์ฑ์ ์ ๊ณตํ์ง๋ง ์ค์ ์ด ๋ ๋ณต์กํ ์ ์์ต๋๋ค.
์ ์ ๋ถ์: ์ฒซ ๋ฒ์งธ ๋ฐฉ์ด์
ํ ์คํธ๊ฐ ์คํ๋๊ธฐ ์ ์๋ ์ ์ ๋ถ์ ๋๊ตฌ๋ ์ผ๋ฐ์ ์ธ ์ค๋ฅ๋ฅผ ์ก์๋ด๊ณ ์ฝ๋ ์คํ์ผ์ ๊ฐ์ ํ ์ ์์ต๋๋ค. ์ด๋ ํญ์ CI ํ์ดํ๋ผ์ธ์ ์ฒซ ๋ฒ์งธ ๋จ๊ณ์ฌ์ผ ํฉ๋๋ค.
- ESLint: ์ ์ฌ์ ์ธ ๋ฒ๊ทธ๋ถํฐ ์คํ์ผ ์๋ฐ์ ์ด๋ฅด๊ธฐ๊น์ง JavaScript ์ฝ๋์ ๋ฌธ์ ๋ฅผ ์ฐพ์ ์์ ํ๋ ๊ณ ๋๋ก ๊ตฌ์ฑ ๊ฐ๋ฅํ ๋ฆฐํฐ์ ๋๋ค.
- Prettier: ํ ์ ์ฒด์ ์ผ๊ด๋ ์ฝ๋ ์คํ์ผ์ ๋ณด์ฅํ์ฌ ํฌ๋งทํ ์ ๋ํ ๋ ผ์์ ์์ ๋ ๋ ๋จ์ ์ธ(opinionated) ์ฝ๋ ํฌ๋งทํฐ์ ๋๋ค.
- TypeScript: JavaScript์ ์ ์ ํ์ ์ ์ถ๊ฐํจ์ผ๋ก์จ, TypeScript๋ ์ฝ๋๊ฐ ์คํ๋๊ธฐ ํจ์ฌ ์ ์ธ ์ปดํ์ผ ์๊ฐ์ ์ ์ฒด ํด๋์ค์ ์ค๋ฅ๋ฅผ ์ก์๋ผ ์ ์์ต๋๋ค.
'์ด๋ป๊ฒ?': CI ํ์ดํ๋ผ์ธ ๊ตฌ์ถ ์ค์ ๊ฐ์ด๋
์ด์ ์ค์ฉ์ ์ธ ๋ถ๋ถ์ผ๋ก ๋์ด๊ฐ๊ฒ ์ต๋๋ค. ์ฐ๋ฆฌ๋ ์ ์ธ๊ณ์ ์ผ๋ก ๊ฐ์ฅ ์ธ๊ธฐ ์๊ณ ์ ๊ทผ์ฑ์ด ์ข์ CI/CD ํ๋ซํผ ์ค ํ๋์ธ GitHub Actions๋ฅผ ์ฌ์ฉํ์ฌ CI ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํ๋ ๋ฐ ์ค์ ์ ๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ ์ด ๊ฐ๋ ๋ค์ GitLab CI/CD๋ Jenkins์ ๊ฐ์ ๋ค๋ฅธ ์์คํ ์๋ ์ง์ ์ ์ผ๋ก ์ ์ฉ ๊ฐ๋ฅํฉ๋๋ค.
์ฌ์ ์๊ตฌ ์ฌํญ
- JavaScript ํ๋ก์ ํธ (Node.js, React, Vue ๋ฑ).
- ํ ์คํธ ํ๋ ์์ํฌ ์ค์น (์ ๋ ํ ์คํธ์๋ Jest, E2E ํ ์คํธ์๋ Cypress๋ฅผ ์ฌ์ฉ).
- GitHub์ ํธ์คํ ๋ ์ฝ๋.
- `package.json` ํ์ผ์ ์ ์๋ ์คํฌ๋ฆฝํธ.
์ผ๋ฐ์ ์ธ `package.json`์๋ ๋ค์๊ณผ ๊ฐ์ ์คํฌ๋ฆฝํธ๊ฐ ์์ ์ ์์ต๋๋ค:
`package.json` ์คํฌ๋ฆฝํธ ์์:
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"lint": "eslint .",
"test": "jest",
"test:ci": "jest --ci --coverage",
"cypress:open": "cypress open",
"cypress:run": "cypress run"
}
1๋จ๊ณ: ์ฒซ GitHub Actions ์ํฌํ๋ก์ฐ ์ค์ ํ๊ธฐ
GitHub Actions๋ ๋ฆฌํฌ์งํ ๋ฆฌ์ `.github/workflows/` ๋๋ ํ ๋ฆฌ์ ์์นํ YAML ํ์ผ๋ก ์ ์๋ฉ๋๋ค. `ci.yml`์ด๋ผ๋ ํ์ผ์ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
ํ์ผ: `.github/workflows/ci.yml`
์ด ์ํฌํ๋ก์ฐ๋ `main` ๋ธ๋์น์ ํธ์๋ ๋๋ง๋ค ๊ทธ๋ฆฌ๊ณ `main`์ ๋์์ผ๋ก ํ๋ ๋ชจ๋ ํ ๋ฆฌํ์คํธ์์ ๋ฆฐํฐ์ ์ ๋ ํ ์คํธ๋ฅผ ์คํํฉ๋๋ค.
# ์ํฌํ๋ก์ฐ์ ์ด๋ฆ์ ๋๋ค.
name: JavaScript CI
# ์ด ์น์ ์ ์ํฌํ๋ก์ฐ๊ฐ ์ธ์ ์คํ๋ ์ง ์ ์ํฉ๋๋ค.
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
# ์ด ์น์ ์ ์คํ๋ ์์ ์ ์ ์ํฉ๋๋ค.
jobs:
# 'test'๋ผ๋ ์ด๋ฆ์ ๋จ์ผ ์์ ์ ์ ์ํฉ๋๋ค.
test:
# ์์ ์ ์คํํ ๊ฐ์ ๋จธ์ ์ ์ข ๋ฅ์ ๋๋ค.
runs-on: ubuntu-latest
# ์คํ ์ ์คํ๋ ์์ ์ ์์๋ฅผ ๋ํ๋ ๋๋ค.
steps:
# 1๋จ๊ณ: ๋ฆฌํฌ์งํ ๋ฆฌ ์ฝ๋๋ฅผ ์ฒดํฌ์์ํฉ๋๋ค.
- name: Checkout code
uses: actions/checkout@v4
# 2๋จ๊ณ: ์ฌ๋ฐ๋ฅธ ๋ฒ์ ์ Node.js๋ฅผ ์ค์ ํฉ๋๋ค.
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm' # npm ์์กด์ฑ ์บ์ฑ์ ํ์ฑํํฉ๋๋ค.
# 3๋จ๊ณ: ํ๋ก์ ํธ ์์กด์ฑ์ ์ค์นํฉ๋๋ค.
- name: Install dependencies
run: npm ci
# 4๋จ๊ณ: ๋ฆฐํฐ๋ฅผ ์คํํ์ฌ ์ฝ๋ ์คํ์ผ์ ํ์ธํฉ๋๋ค.
- name: Run linter
run: npm run lint
# 5๋จ๊ณ: ์ ๋ ๋ฐ ํตํฉ ํ ์คํธ๋ฅผ ์คํํฉ๋๋ค.
- name: Run unit tests
run: npm run test:ci
์ด ํ์ผ์ ์ปค๋ฐํ๊ณ GitHub์ ํธ์ํ๋ฉด CI ํ์ดํ๋ผ์ธ์ด ํ์ฑํ๋ฉ๋๋ค! GitHub ๋ฆฌํฌ์งํ ๋ฆฌ์ 'Actions' ํญ์ผ๋ก ์ด๋ํ์ฌ ์คํ๋๋ ๊ฒ์ ํ์ธํ์ธ์.
2๋จ๊ณ: Cypress๋ก ์๋ํฌ์๋ ํ ์คํธ ํตํฉํ๊ธฐ
E2E ํ ์คํธ๋ ๋ ๋ณต์กํฉ๋๋ค. ์คํ ์ค์ธ ์ ํ๋ฆฌ์ผ์ด์ ์๋ฒ์ ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ํฉ๋๋ค. ์ด๋ฅผ ์ฒ๋ฆฌํ๋๋ก ์ํฌํ๋ก์ฐ๋ฅผ ํ์ฅํ ์ ์์ต๋๋ค. E2E ํ ์คํธ๋ฅผ ์ํ ๋ณ๋์ ์์ ์ ๋ง๋ค์ด ์ ๋ ํ ์คํธ์ ๋ณ๋ ฌ๋ก ์คํ๋๊ฒ ํจ์ผ๋ก์จ ์ ์ฒด ํ๋ก์ธ์ค ์๋๋ฅผ ๋์ผ ์ ์์ต๋๋ค.
๋ง์ ์ค์ ๋จ๊ณ๋ฅผ ๋จ์ํํด์ฃผ๋ ๊ณต์ `cypress-io/github-action`์ ์ฌ์ฉํ ๊ฒ์ ๋๋ค.
์์ ๋ ํ์ผ: `.github/workflows/ci.yml`
name: JavaScript CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
# ์ ๋ ํ ์คํธ ์์ ์ ๋์ผํ๊ฒ ์ ์ง๋ฉ๋๋ค.
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run test:ci
# E2E ํ ์คํธ๋ฅผ ์ํ ์๋ก์ด ๋ณ๋ ฌ ์์ ์ ์ถ๊ฐํฉ๋๋ค.
e2e-tests:
runs-on: ubuntu-latest
# ์ด ์์ ์ unit-tests ์์ ์ด ์ฑ๊ณตํด์ผ๋ง ์คํ๋ฉ๋๋ค.
needs: unit-tests
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
# ๊ณต์ Cypress ์ก์ ์ ์ฌ์ฉํฉ๋๋ค.
- name: Cypress run
uses: cypress-io/github-action@v6
with:
# E2E ํ ์คํธ ์คํ ์ ์ ์ฑ์ ๋น๋ํด์ผ ํฉ๋๋ค.
build: npm run build
# ๋ก์ปฌ ์๋ฒ๋ฅผ ์์ํ๋ ๋ช ๋ น์ด์ ๋๋ค.
start: npm start
# ํ ์คํธ์ ์ฌ์ฉํ ๋ธ๋ผ์ฐ์ ์ ๋๋ค.
browser: chrome
# ์ด URL์์ ์๋ฒ๊ฐ ์ค๋น๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค.
wait-on: 'http://localhost:3000'
์ด ์ค์ ์ ๋ ๊ฐ์ ์์ ์ ์์ฑํฉ๋๋ค. `e2e-tests` ์์ ์ `unit-tests` ์์ ์ `needs`(ํ์)๋ก ํ๋ฏ๋ก, ์ฒซ ๋ฒ์งธ ์์ ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋ ํ์๋ง ์์๋ฉ๋๋ค. ์ด๋ ์์ฐจ์ ์ธ ํ์ดํ๋ผ์ธ์ ๋ง๋ค์ด, ๋ ๋๋ฆฌ๊ณ ๋น์ฉ์ด ๋ง์ด ๋๋ E2E ํ ์คํธ๋ฅผ ์คํํ๊ธฐ ์ ์ ๊ธฐ๋ณธ์ ์ธ ์ฝ๋ ํ์ง์ ๋ณด์ฅํฉ๋๋ค.
๋์ฒด CI/CD ํ๋ซํผ: ๊ธ๋ก๋ฒ ๊ด์
GitHub Actions๋ ํ๋ฅญํ ์ ํ์ด์ง๋ง, ์ ์ธ๊ณ์ ๋ง์ ์กฐ์ง๋ค์ ๋ค๋ฅธ ๊ฐ๋ ฅํ ํ๋ซํผ์ ์ฌ์ฉํฉ๋๋ค. ํต์ฌ ๊ฐ๋ ์ ๋ณดํธ์ ์ ๋๋ค.
GitLab CI/CD
GitLab์ ๋งค์ฐ ํตํฉ์ ์ด๊ณ ๊ฐ๋ ฅํ CI/CD ์๋ฃจ์ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ค์ ์ ๋ฆฌํฌ์งํ ๋ฆฌ ๋ฃจํธ์ `.gitlab-ci.yml` ํ์ผ์ ํตํด ์ด๋ฃจ์ด์ง๋๋ค.
๊ฐ๋จํ `.gitlab-ci.yml` ์์:
image: node:20
cache:
paths:
- node_modules/
stages:
- setup
- test
install_dependencies:
stage: setup
script:
- npm ci
run_unit_tests:
stage: test
script:
- npm run test:ci
run_linter:
stage: test
script:
- npm run lint
Jenkins
Jenkins๋ ํ์ฅ์ฑ์ด ๋ฐ์ด๋ ์์ฒด ํธ์คํ ์๋ํ ์๋ฒ์ ๋๋ค. ์ต๋์ ์ ์ด์ ์ฌ์ฉ์ ์ ์๊ฐ ํ์ํ ๊ธฐ์ ํ๊ฒฝ์์ ์ธ๊ธฐ ์๋ ์ ํ์ ๋๋ค. Jenkins ํ์ดํ๋ผ์ธ์ ์ผ๋ฐ์ ์ผ๋ก `Jenkinsfile`์ ์ ์๋ฉ๋๋ค.
๊ฐ๋จํ ์ ์ธ์ `Jenkinsfile` ์์:
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'npm ci'
}
}
stage('Test') {
steps {
sh 'npm run lint'
sh 'npm run test:ci'
}
}
}
}
๊ณ ๊ธ CI ์ ๋ต ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
๊ธฐ๋ณธ ํ์ดํ๋ผ์ธ์ ์คํํ ํ์๋ ์๋์ ํจ์จ์ฑ์ ์ํด ์ต์ ํํ ์ ์์ผ๋ฉฐ, ์ด๋ ํนํ ํฌ๊ณ ๋ถ์ฐ๋ ํ์๊ฒ ์ค์ํฉ๋๋ค.
๋ณ๋ ฌ ์ฒ๋ฆฌ์ ์บ์ฑ
๋ณ๋ ฌ ์ฒ๋ฆฌ(Parallelization): ๋๊ท๋ชจ ํ ์คํธ ์ค์ํธ์ ๊ฒฝ์ฐ, ๋ชจ๋ ํ ์คํธ๋ฅผ ์์ฐจ์ ์ผ๋ก ์คํํ๋ฉด ์ค๋ ์๊ฐ์ด ๊ฑธ๋ฆด ์ ์์ต๋๋ค. ๋๋ถ๋ถ์ E2E ํ ์คํธ ๋๊ตฌ์ ์ผ๋ถ ์ ๋ ํ ์คํธ ๋ฌ๋๋ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ์ง์ํฉ๋๋ค. ์ด๋ ํ ์คํธ ์ค์ํธ๋ฅผ ๋์์ ์คํ๋๋ ์ฌ๋ฌ ๊ฐ์ ๋จธ์ ์ ๋ถ์ฐ์ํค๋ ๊ฒ์ ํฌํจํฉ๋๋ค. Cypress Dashboard์ ๊ฐ์ ์๋น์ค๋ CI ํ๋ซํผ์ ๋ด์ฅ ๊ธฐ๋ฅ์ด ์ด๋ฅผ ๊ด๋ฆฌํ์ฌ ์ด ํ ์คํธ ์๊ฐ์ ๋ํญ ์ค์ผ ์ ์์ต๋๋ค.
์บ์ฑ(Caching): ๋ชจ๋ CI ์คํ ์ `node_modules`๋ฅผ ๋ค์ ์ค์นํ๋ ๊ฒ์ ์๊ฐ์ด ๋ง์ด ๊ฑธ๋ฆฝ๋๋ค. ๋ชจ๋ ์ฃผ์ CI ํ๋ซํผ์ ์ด๋ฌํ ์์กด์ฑ์ ์บ์ํ๋ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค. GitHub Actions ์์ (`cache: 'npm'`)์์ ๋ณด์๋ฏ์ด, ์ฒซ ์คํ์ ๋๋ฆฌ์ง๋ง ํ์ ์คํ์ ๋ชจ๋ ๊ฒ์ ๋ค์ ๋ค์ด๋ก๋ํ๋ ๋์ ์บ์๋ฅผ ๋ณต์ํ ์ ์์ผ๋ฏ๋ก ํจ์ฌ ๋น ๋ฆ ๋๋ค.
์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง ๋ณด๊ณ
์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง๋ ํ ์คํธ์ ์ํด ์คํ๋๋ ์ฝ๋์ ๋น์จ์ ์ธก์ ํฉ๋๋ค. 100% ์ปค๋ฒ๋ฆฌ์ง๊ฐ ํญ์ ์ค์ฉ์ ์ด๊ฑฐ๋ ์ ์ฉํ ๋ชฉํ๋ ์๋์ง๋ง, ์ด ์งํ๋ฅผ ์ถ์ ํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ ํ ์คํธ๋์ง ์์ ๋ถ๋ถ์ ์๋ณํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค. Jest์ ๊ฐ์ ๋๊ตฌ๋ ์ปค๋ฒ๋ฆฌ์ง ๋ณด๊ณ ์๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. Codecov๋ Coveralls์ ๊ฐ์ ์๋น์ค๋ฅผ CI ํ์ดํ๋ผ์ธ์ ํตํฉํ์ฌ ์๊ฐ ๊ฒฝ๊ณผ์ ๋ฐ๋ฅธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ถ์ ํ๊ณ , ์ปค๋ฒ๋ฆฌ์ง๊ฐ ํน์ ์๊ณ๊ฐ ์๋๋ก ๋จ์ด์ง๋ฉด ๋น๋๋ฅผ ์คํจ์ํฌ ์๋ ์์ต๋๋ค.
Codecov์ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ ๋ก๋ํ๋ ์คํ ์์:
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
๋น๋ฐ(Secrets) ๋ฐ ํ๊ฒฝ ๋ณ์ ์ฒ๋ฆฌ
์ ํ๋ฆฌ์ผ์ด์ ์ ํนํ E2E ํ ์คํธ๋ฅผ ์ํด API ํค, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๊ฒฉ ์ฆ๋ช ๋๋ ๊ธฐํ ๋ฏผ๊ฐํ ์ ๋ณด๊ฐ ํ์ํ ์ ์์ต๋๋ค. ์ด๋ฌํ ์ ๋ณด๋ฅผ ์ฝ๋์ ์ง์ ์ปค๋ฐํด์๋ ์ ๋ ์ ๋ฉ๋๋ค. ๋ชจ๋ CI ํ๋ซํผ์ ๋น๋ฐ์ ์์ ํ๊ฒ ์ ์ฅํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
- GitHub Actions์์๋ `Settings > Secrets and variables > Actions`์ ์ ์ฅํ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ `${{ secrets.MY_API_KEY }}`์ ๊ฐ์ด `secrets` ์ปจํ ์คํธ๋ฅผ ํตํด ์ํฌํ๋ก์ฐ์์ ์ ๊ทผํ ์ ์์ต๋๋ค.
- GitLab CI/CD์์๋ `Settings > CI/CD > Variables`์์ ๊ด๋ฆฌ๋ฉ๋๋ค.
- Jenkins์์๋ ๋ด์ฅ๋ Credentials Manager๋ฅผ ํตํด ์๊ฒฉ ์ฆ๋ช ์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
์กฐ๊ฑด๋ถ ์ํฌํ๋ก์ฐ ๋ฐ ์ต์ ํ
๋ชจ๋ ์ปค๋ฐ์ ๋ํด ๋ชจ๋ ์์ ์ ์คํํ ํ์๋ ์์ต๋๋ค. ์๊ฐ๊ณผ ์์์ ์ ์ฝํ๊ธฐ ์ํด ํ์ดํ๋ผ์ธ์ ์ต์ ํํ ์ ์์ต๋๋ค:
- ๋น์ฉ์ด ๋ง์ด ๋๋ E2E ํ ์คํธ๋ ํ ๋ฆฌํ์คํธ๋ `main` ๋ธ๋์น๋ก์ ๋ณํฉ ์์๋ง ์คํํฉ๋๋ค.
- `paths-ignore`๋ฅผ ์ฌ์ฉํ์ฌ ๋ฌธ์๋ง ๋ณ๊ฒฝ๋ ๊ฒฝ์ฐ์๋ CI ์คํ์ ๊ฑด๋๋๋๋ค.
- ๋งคํธ๋ฆญ์ค ์ ๋ต์ ์ฌ์ฉํ์ฌ ์ฌ๋ฌ Node.js ๋ฒ์ ์ด๋ ์ด์ ์ฒด์ ์ ๋ํด ๋์์ ์ฝ๋๋ฅผ ํ ์คํธํฉ๋๋ค.
CI๋ฅผ ๋์ด: ์ง์์ ๋ฐฐํฌ(CD)๋ก ๊ฐ๋ ๊ธธ
์ง์์ ํตํฉ์ ๋ฐฉ์ ์์ ์ ๋ฐ๋ถ์ ๋๋ค. ์์ฐ์ค๋ฌ์ด ๋ค์ ๋จ๊ณ๋ ์ง์์ ์ ๋ฌ(Continuous Delivery) ๋๋ ์ง์์ ๋ฐฐํฌ(Continuous Deployment, CD)์ ๋๋ค.
- ์ง์์ ์ ๋ฌ: ๋ฉ์ธ ๋ธ๋์น์์ ๋ชจ๋ ํ ์คํธ๊ฐ ํต๊ณผํ๋ฉด, ์ ํ๋ฆฌ์ผ์ด์ ์ด ์๋์ผ๋ก ๋น๋๋๊ณ ๋ฆด๋ฆฌ์ค ์ค๋น๊ฐ ๋ฉ๋๋ค. ํ๋ก๋์ ์ ๋ฐฐํฌํ๊ธฐ ์ํด์๋ ์ต์ข ์ ์ธ ์๋ ์น์ธ ๋จ๊ณ๊ฐ ํ์ํฉ๋๋ค.
- ์ง์์ ๋ฐฐํฌ: ์ด๋ ํ ๋จ๊ณ ๋ ๋์๊ฐ๋๋ค. ๋ชจ๋ ํ ์คํธ๊ฐ ํต๊ณผํ๋ฉด, ์๋ก์ด ๋ฒ์ ์ด ์ธ๊ฐ์ ๊ฐ์ ์์ด ์๋์ผ๋ก ํ๋ก๋์ ์ ๋ฐฐํฌ๋ฉ๋๋ค.
`main` ๋ธ๋์น๋ก์ ์ฑ๊ณต์ ์ธ ๋ณํฉ ์์๋ง ํธ๋ฆฌ๊ฑฐ๋๋ `deploy` ์์ ์ CI ์ํฌํ๋ก์ฐ์ ์ถ๊ฐํ ์ ์์ต๋๋ค. ์ด ์์ ์ Vercel, Netlify, AWS, Google Cloud ๋๋ ์์ฒด ์๋ฒ์ ๊ฐ์ ํ๋ซํผ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐฐํฌํ๋ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํฉ๋๋ค.
GitHub Actions์ ๊ฐ๋ ์ ๋ฐฐํฌ ์์ :
deploy:
needs: [unit-tests, e2e-tests]
runs-on: ubuntu-latest
# main ๋ธ๋์น์ ํธ์๋ ๋๋ง ์ด ์์ ์ ์คํํฉ๋๋ค.
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
# ... ์ฒดํฌ์์, ์ค์ , ๋น๋ ๋จ๊ณ ...
- name: Deploy to Production
run: ./deploy-script.sh # ๋ฐฐํฌ ๋ช ๋ น์ด
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
๊ฒฐ๋ก : ๋จ์ํ ๋๊ตฌ๊ฐ ์๋ ๋ฌธํ์ ๋ณํ
JavaScript ํ๋ก์ ํธ์ CI ํ์ดํ๋ผ์ธ์ ๊ตฌํํ๋ ๊ฒ์ ๊ธฐ์ ์ ์ธ ์์ ์ ๋์ด ํ์ง, ์๋, ํ์ ์ ๋ํ ์ฝ์์ ๋๋ค. ์ด๋ ์์น์ ๊ด๊ณ์์ด ๋ชจ๋ ํ ๊ตฌ์ฑ์์ด ๊ฐ๋ ฅํ ์๋ํ๋ ์์ ๋ง์ด ์๋ค๋ ๊ฒ์ ์๊ณ ์์ ๊ฐ ์๊ฒ ๊ธฐ์ฌํ ์ ์๋ ๋ฌธํ๋ฅผ ๊ตฌ์ถํฉ๋๋ค.
๋น ๋ฅธ ์ ๋ ํ ์คํธ๋ถํฐ ํฌ๊ด์ ์ธ E2E ์ฌ์ฉ์ ์ฌ์ ์ ์ด๋ฅด๊ธฐ๊น์ง ๊ฒฌ๊ณ ํ ์๋ํ ํ ์คํธ ๊ธฐ๋ฐ์ผ๋ก ์์ํ์ฌ ์ด๋ฅผ ์๋ํ๋ CI ์ํฌํ๋ก์ฐ์ ํตํฉํจ์ผ๋ก์จ ๊ฐ๋ฐ ํ๋ก์ธ์ค๋ฅผ ๋ณํ์ํฌ ์ ์์ต๋๋ค. ๋ฒ๊ทธ๋ฅผ ์์ ํ๋ ๋ฐ์์ ์ธ ์ํ์์ ๋ฒ๊ทธ๋ฅผ ์๋ฐฉํ๋ ์ฌ์ ์ ์ธ ์ํ๋ก ์ ํํ๊ฒ ๋ฉ๋๋ค. ๊ทธ ๊ฒฐ๊ณผ๋ ๋ ํ๋ ฅ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ , ๋ ์์ฐ์ ์ธ ๊ฐ๋ฐํ, ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ์์๊ฒ ๊ฐ์น๋ฅผ ์ด์ ๋ณด๋ค ๋ ๋น ๋ฅด๊ณ ์์ ์ ์ผ๋ก ์ ๊ณตํ ์ ์๋ ๋ฅ๋ ฅ์ ๋๋ค.
์์ง ์์ํ์ง ์์๋ค๋ฉด ์ค๋ ์์ํ์ธ์. ์๊ฒ ์์ํ์ธ์โ์๋ง๋ ๋ฆฐํฐ์ ๋ช ๊ฐ์ ์ ๋ ํ ์คํธ๋ก. ์ ์ฐจ ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ํ์ฅํ๊ณ ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํ์ธ์. ์ด๊ธฐ ํฌ์๋ ์์ ์ฑ, ์๋, ๊ทธ๋ฆฌ๊ณ ๋ง์์ ํํ๋ผ๋ ํํ๋ก ๋ช ๋ฐฐ์ ๋ณด์์ ๊ฐ์ ธ๋ค ์ค ๊ฒ์ ๋๋ค.