CI/CD 스터디 04: Build, Test, Quality Gate
Build, lint, unit/integration test, coverage, test artifact, 품질 게이트를 CI 파이프라인에서 어떻게 배치할지 정리합니다.
CI는 코드를 자동으로 빌드하는 기능이 아니라, 운영에 올리면 안 되는 변경을 최대한 앞에서 걸러내는 품질 게이트입니다.
품질 게이트의 목적
좋은 CI는 모든 테스트를 많이 돌리는 것이 아니라, 변경 위험을 빠르게 분류합니다. format/lint는 수십 초 안에 실패해야 하고, unit test는 개발자에게 즉시 피드백을 줘야 하며, integration/e2e test는 운영 장애를 만들 수 있는 흐름을 검증해야 합니다.
- format: 코드 스타일 논쟁을 자동화로 제거합니다.
- lint/static check: 잠재 오류, 미사용 변수, 위험 API 사용을 찾습니다.
- unit test: 함수와 모듈 단위 회귀를 빠르게 잡습니다.
- integration test: DB, queue, external adapter 같은 경계를 검증합니다.
- build: artifact 또는 container image가 실제로 만들어지는지 확인합니다.
- quality gate: coverage, vulnerability, policy 결과를 merge/deploy 조건으로 연결합니다.
로컬에서 먼저 재현하기
CI에서만 실패하는 테스트는 디버깅 비용이 큽니다. 따라서 파이프라인 명령은 로컬에서도 거의 같은 순서로 실행 가능해야 합니다.
# Node.js 예시
npm ci
npm run format:check
npm run lint
npm test
npm run build
# Python 예시
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
python -m pytest -q
python -m compileall .
# Maven 예시
mvn -B -ntp test
mvn -B -ntp package
# Go 예시
go test ./...
go build ./...테스트 리포트와 artifact
테스트가 실패했을 때 로그만 남기면 원인 분석이 느립니다. JUnit XML, coverage report, browser screenshot, e2e trace 같은 산출물을 artifact로 남기면 실패를 재현하기 쉽습니다.
test:
stage: test
image: python:3.12-slim
script:
- pip install -r requirements.txt
- pytest --junitxml=reports/junit.xml --cov=app --cov-report=xml:reports/coverage.xml
artifacts:
when: always
reports:
junit: reports/junit.xml
coverage_report:
coverage_format: cobertura
path: reports/coverage.xml
paths:
- reports/
expire_in: 14 daysGitHub Actions 품질 게이트 예시
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
- run: npm ci
- run: npm run lint
- run: npm test -- --ci
- run: npm run build
- name: Upload test reports
if: always()
uses: actions/upload-artifact@v4
with:
name: test-reports
path: reports/게이트 강도 조절
| 브랜치/이벤트 | 권장 게이트 | 이유 |
|---|---|---|
| feature branch | format, lint, unit test | 개발자 feedback 속도가 중요합니다. |
| pull/merge request | unit, integration, build, policy | main에 들어가기 전 회귀를 막습니다. |
| main push | 전체 test, image build, scan, staging deploy | 배포 가능한 산출물을 만듭니다. |
| release tag | 재빌드 또는 digest pin 검증, production approval | 운영 변경 이력을 고정합니다. |
실무 판단 기준
- 항상 먼저 실패해야 하는 검사는 앞쪽 job에 둡니다.
- 느린 e2e test는 모든 commit보다 main 또는 nightly로 분리할 수 있습니다.
- 테스트가 flaky하면 재시도보다 원인 분류가 먼저입니다. flaky test는 신뢰를 갉아먹습니다.
- coverage 숫자만 보지 말고, 운영 장애를 만들었던 경로가 test로 고정됐는지 확인합니다.
- 품질 게이트 실패는 우회보다 기록과 예외 만료일이 중요합니다.