{ "name": "Testing Rules", "description": "테스트 코드 작성 및 실행을 위한 규칙", "rules": { "coverage": { "minimum": 80, "excludePatterns": [ "**/*.test.ts", "**/*.spec.ts", "**/__tests__/**" ] }, "naming": { "testFiles": "*.test.ts", "testPattern": "describe('Component', () => {})" }, "structure": { "arrange": true, "act": true, "assert": true }, "mocking": { "preferSpyOn": true, "mockImplementation": true }, "testTypes": { "unit": { "description": "개별 함수/클래스/컴포넌트를 독립적으로 테스트", "scope": "단일 모듈 또는 함수", "dependencies": "모두 목/스텁 처리", "frameworks": ["Jest", "Vitest", "Mocha", "Pytest"], "guidelines": [ "각 테스트는 하나의 동작 또는 결과만 검증", "외부 의존성 모두 격리", "테스트 간 독립성 유지 (상태 공유 없음)", "빠른 실행 시간 유지" ], "patterns": { "sut": "테스트 대상 모듈 명확히 식별", "factory": "테스트 데이터/객체 생성 함수 활용", "minimal": "테스트에 필요한 최소한의 설정만 포함" } }, "integration": { "description": "여러 모듈/서비스 간 상호작용 테스트", "scope": "모듈 간 경계, API 엔드포인트, 데이터베이스 연동", "dependencies": "일부는 실제 구현체 사용, 외부 서비스는 목 처리", "frameworks": ["Supertest", "TestContainers", "Spring Boot Test"], "guidelines": [ "핵심 통합 경로 위주로 테스트", "실제 환경과 유사한 구성 사용", "격리된 테스트 환경 구성", "외부 의존성 최소화" ], "patterns": { "testDatabase": "인메모리 DB 또는 테스트 전용 DB 인스턴스 사용", "apiTesting": "엔드포인트 응답 형식 및 상태 코드 검증", "dataFlow": "시스템 경계 간 데이터 흐름 검증" } }, "e2e": { "description": "사용자 관점에서 전체 시스템 흐름 테스트", "scope": "전체 애플리케이션 흐름", "dependencies": "가능한 실제 구현체 사용", "frameworks": ["Cypress", "Playwright", "Selenium", "Puppeteer"], "guidelines": [ "중요 사용자 시나리오 위주로 테스트", "테스트 안정성을 위한 대기 전략 구현", "독립적인 테스트 데이터 관리", "병렬 실행 가능하도록 구성" ], "patterns": { "pageObjects": "화면 상호작용 로직 캡슐화", "fixtures": "테스트 데이터 외부화", "screenshots": "실패 시 스크린샷 캡처", "video": "테스트 실행 녹화" } }, "performance": { "description": "시스템 성능 특성 검증", "scope": "응답 시간, 처리량, 자원 사용량", "frameworks": ["JMeter", "K6", "Gatling", "Artillery"], "guidelines": [ "명확한 성능 지표 및 기준 정의", "대표적인 사용자 패턴 시뮬레이션", "다양한 부하 시나리오 테스트", "성능 저하 추세 모니터링" ], "metrics": [ "응답 시간 (평균, 중앙값, 95/99 백분위)", "초당 요청 처리량", "오류율", "시스템 자원 사용량(CPU, 메모리, I/O)" ] }, "security": { "description": "보안 취약점 검출", "scope": "인증/인가, 입력 검증, 세션 관리", "frameworks": ["OWASP ZAP", "SonarQube", "Snyk"], "guidelines": [ "OWASP TOP 10 취약점 대응 검증", "인증 및 권한 부여 로직 집중 테스트", "입력 검증 우회 테스트", "민감 정보 노출 확인" ], "checkTypes": [ "인증 우회 테스트", "권한 상승 테스트", "SQL 인젝션 테스트", "XSS 취약점 테스트", "CSRF 방어 테스트" ] } }, "testData": { "management": { "fixtures": { "location": "테스트 데이터는 별도 디렉토리(/__fixtures__/)에 보관", "format": "JSON, YAML 또는 JavaScript/TypeScript 객체", "naming": "목적을 명확히 표현하는 이름 사용" }, "factories": { "purpose": "테스트 객체 생성 로직 재사용", "implementation": "Factory 함수 또는 Builder 패턴 사용", "examples": [ "createUser({ ...customProps })", "new UserBuilder().withName().withRole().build()" ] }, "mocks": { "purpose": "외부 의존성 시뮬레이션", "frameworks": ["Jest Mock", "Sinon", "MockK", "pytest-mock"], "guidelines": [ "최소한의 필요 동작만 목 처리", "재사용 가능한 목 구성", "목의 동작 명시적 정의" ] } }, "bestPractices": { "isolation": "테스트 간 데이터 독립성 보장", "deterministic": "시간, 랜덤 값 등 비결정적 요소 목 처리", "realistic": "실제 데이터와 유사한 테스트 데이터 구성", "maintenance": "중앙화된 테스트 데이터 관리로 유지보수성 향상" }, "databaseTesting": { "approach": [ "인메모리 데이터베이스 사용", "테스트 전용 DB 인스턴스 사용", "테스트 후 상태 롤백" ], "tools": ["TestContainers", "H2", "SQLite", "MongoDB Memory Server"], "dataSeeding": "테스트 실행 전 필요 데이터 시드 삽입", "cleanup": "각 테스트 종료 후 데이터 정리" } }, "automationPipeline": { "ci": { "triggers": [ "모든 Pull Request", "메인 브랜치 커밋", "릴리스 태그 생성" ], "stages": [ "린트 및 정적 분석", "단위 테스트", "통합 테스트", "E2E 테스트(주요 시나리오)", "보안 스캔" ], "optimizations": [ "변경된 파일 관련 테스트만 실행", "테스트 병렬 실행", "테스트 결과 캐싱" ] }, "reporting": { "formats": ["JUnit XML", "HTML 리포트", "JSON"], "metrics": [ "테스트 성공/실패 수", "코드 커버리지", "테스트 실행 시간" ], "visualization": "테스트 결과 대시보드 구성", "notification": "실패 시 알림 전송" }, "environments": { "dev": "개발자 로컬 환경, 빠른 피드백 루프", "ci": "격리된 통합 환경, 재현 가능한 결과", "staging": "프로덕션 유사 환경, 전체 테스트 스위트 실행" }, "flakiness": { "detection": "불안정한 테스트 식별 및 태그 지정", "remediation": "비결정적 요소 제거, 명시적 대기 구현", "retry": "불안정한 테스트는 실패 시 제한된 재시도 허용" } }, "advancedTechniques": { "propertyBased": { "description": "다양한 입력 조합에 대한 속성 검증", "frameworks": ["fast-check", "jsverify", "hypothesis"], "applications": [ "유효성 검사 로직", "데이터 변환 함수", "상태 머신 동작" ], "guidelines": [ "검증할 속성 명확히 정의", "경계값 중심 생성기 구성", "실패 사례 최소화 및 저장" ], "example": { "js": "fc.property(fc.string(), s => reverse(reverse(s)) === s)" } }, "snapshot": { "description": "출력 결과의 일관성 검증", "applications": [ "UI 컴포넌트 렌더링 결과", "API 응답 구조", "복잡한 객체 직렬화 결과" ], "frameworks": ["Jest Snapshots", "Enzyme", "react-test-renderer"], "guidelines": [ "스냅샷은 코드 리뷰 과정에서 신중히 검토", "불필요한 세부 정보는 직렬화에서 제외", "날짜, ID 등 가변값은 정규화", "의도적 변경 시 스냅샷 업데이트" ], "maintenance": "정기적인 스냅샷 검토 및 정리" }, "mutation": { "description": "테스트 품질 검증을 위한 코드 변형", "frameworks": ["Stryker", "Pitest"], "process": [ "소스 코드 연산자/값 변형", "변형된 코드로 테스트 실행", "테스트 실패 여부 확인" ], "metrics": "변형 점수(높을수록 테스트 품질 우수)", "optimization": "비용 고려하여 CI에서 제한적 실행" }, "fuzzing": { "description": "무작위/비정상 입력으로 견고성 테스트", "applications": [ "파서/직렬화 함수", "사용자 입력 처리", "파일 처리 로직" ], "approach": [ "유효/무효 입력 경계 집중 탐색", "이전 오류 케이스 재활용", "코드 커버리지 기반 입력 생성" ] } } } }