⸻
1. 서론: 왜 AI로 테스트 순서를 짜야 하나
대규모 모놀리틱→마이크로서비스 전환, CI/CD 파이프라인 고도화, 코드베이스 성장으로 수천 수만 개 테스트를 매번 실행하기엔 시간과 자원이 치명적으로 낭비됩니다. 실리콘밸리·심천 톱티어 기업들은 테스트 실패 확률·코드 변경 영향도를 기반으로 우선순위를 동적으로 재조정해, 최소한의 테스트로 최대한의 결함 탐지를 실현합니다.
• 피드백 루프 단축: 변경된 코드와 연관된 테스트만 빠르게 실행
• 리소스 최적화: 불필요한 테스트 격리·스킵 → 빌드 자원 절감
• AI 예측 정확도: 과거 테스트 히스토리·커버리지·코드 복잡도 데이터 학습
이제 머신러닝 모델을 활용해 Test Suite를 동적 스코어링·샘플링하는 ‘끝판왕’ 전략을 설계해 보겠습니다.
⸻
2. 아키텍처 개요
코드 레포 ──▶ 변경 감지 ──▶ 피처 엔지니어링 ──▶ ML 모델 예측 ──▶
└────────────▶ Test Prioritizer ──▶ CI 파이프라인 (Parallel/Matrix)
1. 변경 감지: Git diff로 수정된 파일·라인 추출
2. 피처 엔지니어링:
• 코드 변경 메트릭: 변경 라인 수, 변경 파일 수, churn rate
• 테스트 메타: 과거 실패율, 실행시간, 커버리지 비율
• 코드 테스트 맵: 어떤 테스트가 어떤 코드 라인을 커버하는지
3. ML 모델 학습:
• 분류/순위 예측 모델(Gradient Boosting, LightGBM, XGBoost)
• Label: 테스트 실패 여부(0/1) 또는 실행 우선순위(0~1 스코어)
4. Test Prioritizer: 스코어 기준 상위 N개 혹은 스코어 합 ≥ T 실행
5. CI 파이프라인: 선택된 테스트만 병렬 실행 → 결과 집계
⸻
3. 데이터 수집 & 피처 엔지니어링
3.1 Git 변경 감지
git diff --name-only origin/main...HEAD > changed_files.txt
git diff --unified=0 origin/main...HEAD | grep -E "^\+[^+]" > changed_lines.diff
• changed_files.txt: 변경된 파일 리스트
• changed_lines.diff: 변경된 라인 번호(정규표현식)
3.2 커버리지 매핑
• Coverage Report: lcov, Jacoco, coverage.py 등으로 라인 단위 커버리지 JSON 생성
• 파싱 스크립트 (Python 예시):
import json
from collections import defaultdict
with open('coverage/coverage-summary.json') as f:
cov = json.load(f)
# 파일 → 라인 커버리지 맵
file_line_map = defaultdict(set)
for file_path, data in cov['files'].items():
for line_no, count in data['lines'].items():
if count > 0:
file_line_map[file_path].add(int(line_no))
3.3 테스트 메타 수집
• 과거 빌드 로그(CI DB)에서:
• test_name, duration, status(pass/fail), timestamp
• 스크립트 예:
SELECT test_name,
AVG(duration) AS avg_time,
SUM(CASE WHEN status='FAIL' THEN 1 ELSE 0 END) / COUNT(*) AS fail_rate
FROM ci_test_history
WHERE repo='my-app'
GROUP BY test_name;
3.4 피처 집계
• Feature Vector per test per commit:
- test_name: test_user_api
changed_files_count: 3
changed_lines_count: 7
overlap_cover_lines: 5
avg_duration: 12.3
fail_rate: 0.08
last_run_days_ago: 2
• Overlap = len(changed_lines ∩ coverage_lines)
⸻
4. ML 모델 설계 & 학습
4.1 모델 선택
• LightGBM (Ranker / Classifier)
• XGBoost with rank:pairwise
• Neural Network (optional): Feed-Forward + Tabular Embedding
4.2 학습 파이프라인 (Python)
import pandas as pd
from lightgbm import LGBMRanker
from sklearn.model_selection import GroupKFold
# 데이터 로드
df = pd.read_csv('features.csv')
X = df.drop(['test_name','score','group'], axis=1)
y = df['score'] # 1: 실패 확률 높음 우선
groups = df['group'] # commit id as group
# Ranker 사용 예
model = LGBMRanker(
objective='lambdarank',
metric='ndcg',
n_estimators=100,
learning_rate=0.1
)
# GroupKFold로 커밋 단위 CV
gkf = GroupKFold(n_splits=5)
for train_idx, val_idx in gkf.split(X, y, groups):
model.fit(
X.iloc[train_idx], y.iloc[train_idx],
group=groups.iloc[train_idx].value_counts().sort_index().values,
eval_set=[(X.iloc[val_idx], y.iloc[val_idx])],
eval_group=[groups.iloc[val_idx].value_counts().sort_index().values],
early_stopping_rounds=10
)
• GroupKFold: 커밋 단위 묶음
• Lambdarank: 순위 예측에 특화된 손실 함수
4.3 모델 서빙
• 학습 완료 모델을 pickle로 저장,
• FastAPI나 Flask로 간단한 예측 서버 구축:
from fastapi import FastAPI
import pickle
import pandas as pd
app = FastAPI()
model = pickle.load(open('lgb_ranker.pkl','rb'))
@app.post('/predict')
def predict(features: list[dict]):
df = pd.DataFrame(features)
scores = model.predict(df)
return {'scores': scores.tolist()}
⸻
5. CI/CD 파이프라인 연동
5.1 GitHub Actions 워크플로우
name: Predict & Run Tests
on: push
jobs:
prioritize-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Detect changes
run: |
git diff --name-only origin/main...HEAD > changed_files.txt
git diff --unified=0 origin/main...HEAD | grep -E "^\+[^+]" > changed_lines.diff
- name: Gather features
run: python scripts/extract_features.py
- name: Predict test scores
run: |
pip install -r requirements.txt
python scripts/predict_tests.py \
--model-path=lgb_ranker.pkl \
--features=features.json \
--output=prioritized_tests.txt
- name: Run top tests
uses: dorny/test-reporter@v1
with:
name: "Top 20 Tests"
command: |
head -n 20 prioritized_tests.txt | xargs -n1 -P4 pytest -q --junitxml=reports/{}.xml
• extract_features.py: 2장 피처 엔지니어링 스크립트
• predict_tests.py: FastAPI 서버 호출 or 직접 model.predict
5.2 Jenkins Pipeline 예시
pipeline {
agent any
stages {
stage('Checkout & Feature Extraction') {
steps {
checkout scm
sh 'python3 scripts/extract_features.py'
}
}
stage('Predict & Select Tests') {
steps {
sh 'python3 scripts/predict_tests.py --model lgb_ranker.pkl --features features.json --top 30 > tests_to_run.txt'
}
}
stage('Execute Prioritized Tests') {
parallel {
script {
def tests = readFile('tests_to_run.txt').split('\n')
def branches = tests.collate(5) // 그룹당 5개씩 병렬
for (int i=0; i<branches.size(); i++) {
def batch = branches[i]
stage("Batch ${i+1}") {
steps {
sh "pytest ${batch.join(' ')} --junitxml=reports/batch${i+1}.xml"
}
}
}
}
}
}
}
}
• batch 그룹화와 병렬 실행으로 피드백 극대화
⸻
6. “아, 이런 방법도 있었구나” 팁
1. 온라인 학습: 테스트 실패 데이터를 스트리밍해 주기적 모델 업데이트 (River, creme 라이브러리)
2. Transfer Learning: 신규 프로젝트에 기존 모델 가중치 활용 후 미세조정
3. Explainability: SHAP으로 각 피처별 예측 기여도 분석 → 팀에 피드백
4. Adaptive Threshold: 전체 테스트 커버리지 목표에 따라 동적 N 자동 조정
5. Dashboard: Grafana + Prometheus로
• 예측 정확도(Precision@K)
• 실행 대비 실패 탐지율
• CI 시간 절감 효과 시각화
⸻
7. 결론
• 데이터 기반으로 Test Suite를 동적 우선순위화
• LightGBM 랭킹 모델로 실패 확률 예측 → 상위 N개 테스트만 실행
• CI/CD에 ML 파이프라인 연동 → 피드백 루프 단축
“교과서엔 절대 없는, 실리콘밸리·심천 IT기업 톱티어 엔지니어급 AI 기반 테스트 최적화”를 직접 구현해 보세요. 최소한의 테스트로 최대한의 안정성을 보장하는 그날까지!
'IT & Tech 정보' 카테고리의 다른 글
자동 롤백 전략 끝판왕 가이드: Helm + Kubernetes Liveness/Readiness 프로브 (0) | 2025.05.26 |
---|---|
Chaos Engineering 통합 끝판왕 가이드: Chaos Mesh & LitmusChaos CI 파이프라인 (0) | 2025.05.26 |
ChatOps 워크플로우 끝판왕 가이드: Slack · Hubot · GitHub Webhook 완전 정복 (0) | 2025.05.26 |
ChatOps 워크플로우 끝판왕 가이드 Slack · Hubot · GitHub Webhook 자동화 (0) | 2025.05.26 |
DB 마이그레이션 자동화 끝판왕 가이드 (0) | 2025.05.26 |