- session-logs, blogwatcher, summarize, whisper, gitea, himalaya, skill-creator SKILL.md - SKILL.md 인덱스 업데이트 (16개 스킬) - 311/314/315 상위 SSOT 중복 제거 + 링크 수정 - Phase 1-3 결과 + 테스트 결과 + evaluation 트러블슈팅 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
193 lines
7.5 KiB
Markdown
193 lines
7.5 KiB
Markdown
# 테스트 원칙
|
|
|
|
**작성일**: 2025-01-03
|
|
**수정일**: 2026-03-26 (상위 SSOT 정렬: 중복 제거, `20_Governance` 경로 정정)
|
|
**상위 원칙**: [0_VALUE Test Principles](../../../../0_VALUE/20_Governance/test-principles.md)
|
|
**참고**: 311_backend_coding_principles.md, 312_writing-principles.md, ../../../../0_VALUE/20_Governance/coding-principles.md
|
|
|
|
---
|
|
|
|
## TDD
|
|
|
|
**테스트는 TDD로 진행한다.**
|
|
|
|
- **Red**: 테스트 먼저 작성 (기대 행동을 테스트에 명시)
|
|
- **Green**: 최소 구현으로 테스트 통과
|
|
- **Refactor**: 리팩터링 후 테스트 재실행
|
|
|
|
DecisionEngine, intent, 캘린더 로직 등은 항상 테스트에서 기대 행동을 확정한 뒤 수정한다.
|
|
|
|
---
|
|
|
|
## 스킬·라우팅 검증
|
|
|
|
상위 원칙 참조: [0_VALUE Test Principles](../../../../0_VALUE/20_Governance/test-principles.md)
|
|
|
|
신규 스킬, 의도 분류, `tool_registry` 변경 후 Slack 실메시지 전 검증은 상위 문서의 테스트 엔드포인트 원칙을 따른다. 로빙 rb8001 예시:
|
|
|
|
```bash
|
|
# JWT 없이 전체 플로우 테스트 (의도 분류 → 스킬 선택 → 실행 → 응답)
|
|
curl -s -X POST http://localhost:8001/api/test/router-message \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"text": "테스트할 메시지", "user_id": "53529291-5050-4daa-89fb-008b546feb63"}'
|
|
```
|
|
|
|
- `text`: 사용자 메시지
|
|
- `user_id`: 선택 (기본값 있음)
|
|
- 응답: `bot_response`, `intent`, `status`
|
|
|
|
---
|
|
|
|
## 로빙 테스트 환경 단일화
|
|
|
|
로빙 테스트는 `robeing/tests`에서 통합 관리한다. rb8001, skill-* 등 서비스별 테스트를 `robeing/tests/rb8001/` 등 하위에 두고, 단일 실행 기준만 사용한다. rb8001 푸시 시 Gitea Actions 배포가 트리거되므로, 테스트 수정만으로 배포를 유발하지 않도록 `robeing/tests`에서 작업한다. 임시/분기 테스트 환경은 만들지 않는다.
|
|
|
|
---
|
|
|
|
## UX 검증
|
|
|
|
- 사용자가 실제로 보는 문구·행동만 검증한다 (예: 응답 문장, 버튼 노출 여부)
|
|
- 내부 안내/제약 설명(“직접 언급 금지” 같은 시스템 지시문)은 금지어 검증 대상이 아님
|
|
- UX 규칙(감정 직접 표현 금지 등)은 사용자 시나리오 테스트로 재현한다
|
|
|
|
---
|
|
|
|
## 공통 원칙(검증 우선·파일 양산 금지·자산 보존·자동·수동 분리·재사용·레이어·운영 경로·체크리스트)
|
|
|
|
목적, 원칙 전항, 유지 기준, 체크리스트는 상위 SSOT와 동일하다.
|
|
|
|
상위 원칙 참조: [0_VALUE Test Principles](../../../../0_VALUE/20_Governance/test-principles.md)
|
|
|
|
---
|
|
|
|
## 로빙 전용 — 테스트 위치 요약
|
|
|
|
| 유형 | 위치 | 관리 방식 |
|
|
|------|------|----------|
|
|
| **로빙 통합 테스트** | `robeing/tests/` (rb8001/, `test_*.py` 등) | robeing 전체 테스트 통합. 배포 트리거 없이 실행. [worklog 260316](../../journey/worklog/260316_rb8001_테스트_로빙테스츠로_이전.md) |
|
|
| **pytest 자동 테스트** | `tests/test_*.py` (레포 내) | 버전 관리, 지속 유지 (`.gitignore` 제외 금지) |
|
|
| **실험·관찰 스크립트** | `scripts/` (임시) | 작업 완료 즉시 삭제 |
|
|
| **공통 fixtures** | `tests/conftest.py` | 상위 재사용 원칙 준수 |
|
|
| **테스트 데이터** | `tests/data/`, `tests/fixtures/` | 공유 가능하도록 구조화 |
|
|
|
|
`tests/`에 실험 스크립트·수동 전용 파일을 두지 않는다. 금지 사유와 자동·수동 구분은 상위 문서를 따른다.
|
|
|
|
---
|
|
|
|
## fixtures·테스트 데이터 예시
|
|
|
|
**권장**: pytest fixtures
|
|
|
|
```python
|
|
# tests/conftest.py
|
|
@pytest.fixture
|
|
def mock_llm_service():
|
|
"""LLM 서비스 모킹 - 모든 테스트에서 재사용"""
|
|
with patch('app.services.llm.llm_service.LLMService') as mock:
|
|
yield mock
|
|
|
|
# tests/test_intent.py
|
|
def test_intent_classification(mock_llm_service):
|
|
# mock_llm_service 자동 주입
|
|
...
|
|
```
|
|
|
|
**권장 데이터 경로**: `tests/data/intent_eval_samples.json`, `tests/fixtures/`
|
|
|
|
**금지**: 동일 모킹·데이터를 테스트 파일마다 복붙
|
|
|
|
상위의 재사용·중복 금지 원칙과 함께 적용한다.
|
|
|
|
상위 원칙 참조: [0_VALUE Test Principles](../../../../0_VALUE/20_Governance/test-principles.md)
|
|
|
|
---
|
|
|
|
## 중복 통합·임시 정리 — 로빙에서 자주 보는 패턴
|
|
|
|
| 중복 패턴 | 처리 방법 |
|
|
|-----------|----------|
|
|
| `test_overlap_cases.py` + `test_overlap_tdd.py` | 하나로 통합 (최종 버전 유지) |
|
|
| TDD 단계별 테스트 파일 | 최종 버전만 유지 |
|
|
| `test_*_vs_*.py` 비교 테스트 | troubleshooting 기록 후 삭제 |
|
|
|
|
임시·비교·수동 스크립트 정리 시점과 유지·삭제 기준은 상위 문서를 따른다.
|
|
|
|
상위 원칙 참조: [0_VALUE Test Principles](../../../../0_VALUE/20_Governance/test-principles.md)
|
|
|
|
---
|
|
|
|
## pytest 실행 확인·컨테이너에 테스트 반영
|
|
|
|
상위 원칙 참조: [0_VALUE Test Principles](../../../../0_VALUE/20_Governance/test-principles.md) (`tests/`에는 자동 회귀용 pytest만, `if __name__` 중심 수동 파일 배치 금지 등)
|
|
|
|
**로빙 운영 확인용**:
|
|
|
|
```bash
|
|
pytest tests/test_*.py -v
|
|
grep -l "import pytest\|@pytest" tests/test_*.py
|
|
```
|
|
|
|
**컨테이너**: `tests`는 볼륨 마운트가 아니라 Dockerfile에서 `COPY ./tests /code/tests`로 빌드 시에만 반영된다.
|
|
|
|
새 테스트 파일을 컨테이너에 올릴 때:
|
|
|
|
```bash
|
|
# 방법 1: docker cp (빠름, 재빌드 불필요)
|
|
docker cp tests/test_new_feature.py rb8001:/code/tests/
|
|
|
|
# 방법 2: 컨테이너 재빌드 (확실함)
|
|
docker compose down && docker compose up -d --build
|
|
```
|
|
|
|
호스트에서 수정한 테스트가 컨테이너에 자동 반영되지 않는다는 점에 주의한다.
|
|
|
|
---
|
|
|
|
## 파일명·디렉터리 구조
|
|
|
|
| 패턴 | 용도 | 예시 |
|
|
|------|------|------|
|
|
| `test_{기능}.py` | 기능 단위 테스트 | `test_intent_classification.py` |
|
|
| `test_{엔드포인트}_endpoint.py` | API 엔드포인트 테스트 | `test_diary_endpoint.py` |
|
|
| `e2e/test_{워크플로우}.py` | E2E 테스트 | `e2e/test_coldmail_full_flow.py` |
|
|
|
|
**피할 네이밍**
|
|
|
|
- `test_*_refactoring.py` (작업 완료 후 삭제)
|
|
- `test_*_vs_*.py` (비교 실험, 결과 기록 후 삭제)
|
|
- `e2e_*.py` (tests 루트에 두지 말고 `e2e/` 아래로)
|
|
- 중복 E2E: `test_e2e_*.py`와 `test_*_e2e.py` (하나로 통합)
|
|
|
|
---
|
|
|
|
## 로빙 체크리스트(상위에 더함)
|
|
|
|
상위 원칙 참조: [0_VALUE Test Principles](../../../../0_VALUE/20_Governance/test-principles.md)
|
|
|
|
- [ ] TDD 순서 (Red → Green → Refactor)
|
|
- [ ] 통합 작업은 `robeing/tests` 기준으로 할 것 (배포 트리거·환경 단일화)
|
|
- [ ] 스킬·라우팅 변경 후 `/api/test/router-message` 등 테스트 엔드포인트로 선검증
|
|
- [ ] 컨테이너로 돌릴 때 테스트 파일 반영 경로(`docker cp` / 재빌드) 확인
|
|
- [ ] `.gitignore`에 `tests/test_*.py` 제외 규칙 없음
|
|
|
|
---
|
|
|
|
## 정리 사례 (2025-01-03)
|
|
|
|
**삭제된 파일**:
|
|
|
|
1. `test_calendar_intent_overlap_cases.py` — “서비스 코드 수정 없이 관찰” 목적, 수동 실행
|
|
2. `test_calendar_query_vs_create.py` — `python3` 직접 실행, pytest 미적용
|
|
3. `test_all_day_event_simple.py` — 수동 실행 스크립트
|
|
4. `e2e/test_e2e_message_flow.py` — “pytest 없이 직접 실행” 주석, 중복 (`test_message_flow_e2e.py` 존재)
|
|
|
|
**결과**: 68개 → 64개 (pytest 자동 테스트만 유지)
|
|
|
|
---
|
|
|
|
## 참고
|
|
|
|
- FastAPI·백엔드: `311_backend_coding_principles.md` (테스트 관련 절)
|
|
- 문서 작성: `312_writing-principles.md` (troubleshooting 기록 방법)
|
|
- 트러블슈팅: `journey/troubleshooting/251110_레거시_테스트_폴더_정리.md`
|