Initial commit
This commit is contained in:
11
.claude-plugin/plugin.json
Normal file
11
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "test-generator",
|
||||
"description": "Automatically generate and run tests with detailed reports",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "Lightsoft"
|
||||
},
|
||||
"commands": [
|
||||
"./commands"
|
||||
]
|
||||
}
|
||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# test-generator
|
||||
|
||||
Automatically generate and run tests with detailed reports
|
||||
673
commands/test.md
Normal file
673
commands/test.md
Normal file
@@ -0,0 +1,673 @@
|
||||
---
|
||||
description: Automatically generate and run tests with detailed reports
|
||||
---
|
||||
|
||||
# Test Generator
|
||||
|
||||
테스트 코드를 자동으로 생성하고 실행한 뒤, 상세한 결과 리포트를 제공합니다.
|
||||
|
||||
## Steps to follow:
|
||||
|
||||
### 1. 테스트 대상 파일 선택
|
||||
|
||||
사용자에게 테스트할 파일을 물어보세요:
|
||||
- IDE에서 현재 열려있는 파일이 있다면 제안
|
||||
- 또는 파일 경로를 직접 입력받기
|
||||
- 예: `src/utils/calculator.js`, `components/Button.tsx`
|
||||
|
||||
**파일이 선택되면 Read 도구로 파일 내용을 읽으세요.**
|
||||
|
||||
### 2. 테스트 유형 선택
|
||||
|
||||
사용자에게 다음 중 선택하도록 안내:
|
||||
|
||||
#### A. 단위 테스트 (Unit Test)
|
||||
- 개별 함수, 메서드, 유틸리티 테스트
|
||||
- 외부 의존성 없이 독립적으로 동작
|
||||
- 가장 빠르고 간단한 테스트
|
||||
|
||||
#### B. 통합 테스트 (Integration Test)
|
||||
- 여러 모듈/컴포넌트 간 상호작용 테스트
|
||||
- API + Database, Service + Repository 등
|
||||
- 실제 의존성과 함께 테스트
|
||||
|
||||
#### C. E2E 테스트 (End-to-End)
|
||||
- 실제 사용자 시나리오 테스트
|
||||
- 브라우저 자동화, 전체 플로우 검증
|
||||
- 가장 현실적이지만 느림
|
||||
|
||||
사용자의 선택을 기록하세요.
|
||||
|
||||
### 3. 테스트 프레임워크 감지
|
||||
|
||||
프로젝트의 `package.json`을 읽고 설치된 테스트 도구를 확인:
|
||||
|
||||
**유닛/통합 테스트 프레임워크:**
|
||||
- `jest`: Jest
|
||||
- `vitest`: Vitest
|
||||
- `mocha` + `chai`: Mocha
|
||||
- `@testing-library/react`: React Testing Library
|
||||
- `@testing-library/vue`: Vue Testing Library
|
||||
|
||||
**E2E 테스트 프레임워크:**
|
||||
- `cypress`: Cypress
|
||||
- `@playwright/test`: Playwright
|
||||
- `puppeteer`: Puppeteer
|
||||
|
||||
**프레임워크가 없는 경우:**
|
||||
- 사용자에게 추천 (Jest/Vitest for unit, Playwright for E2E)
|
||||
- 설치 여부 물어보기
|
||||
- 설치한다면: `npm install -D [프레임워크]`
|
||||
|
||||
### 4. 코드 분석
|
||||
|
||||
읽은 파일 내용을 분석하여 다음을 추출:
|
||||
|
||||
#### JavaScript/TypeScript 파일:
|
||||
- **함수 목록**: export된 함수들
|
||||
- **클래스 및 메서드**: class 정의와 메서드들
|
||||
- **입력 파라미터**: 각 함수의 매개변수
|
||||
- **반환 타입**: TypeScript의 경우 타입 정보
|
||||
- **의존성**: import 문
|
||||
|
||||
**예시 분석 결과:**
|
||||
```
|
||||
파일: src/utils/math.js
|
||||
함수:
|
||||
1. add(a, b) - 두 수를 더함
|
||||
2. subtract(a, b) - 두 수를 뺌
|
||||
3. multiply(a, b) - 두 수를 곱함
|
||||
4. divide(a, b) - 나눗셈 (0으로 나누기 체크 필요)
|
||||
```
|
||||
|
||||
#### React/Vue 컴포넌트:
|
||||
- **컴포넌트 이름**
|
||||
- **Props**: 받는 props와 타입
|
||||
- **이벤트 핸들러**: onClick, onChange 등
|
||||
- **상태**: useState, data() 등
|
||||
|
||||
#### API/백엔드 코드:
|
||||
- **라우트/엔드포인트**: GET, POST 등
|
||||
- **요청/응답 스키마**
|
||||
- **에러 핸들링**
|
||||
|
||||
### 5. 테스트 코드 자동 생성
|
||||
|
||||
선택한 테스트 유형과 프레임워크에 맞는 테스트 코드를 생성:
|
||||
|
||||
---
|
||||
|
||||
#### A. 단위 테스트 생성 예시
|
||||
|
||||
**대상 파일: `src/utils/math.js`**
|
||||
```javascript
|
||||
export function add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
export function divide(a, b) {
|
||||
if (b === 0) throw new Error('Division by zero');
|
||||
return a / b;
|
||||
}
|
||||
```
|
||||
|
||||
**생성할 테스트: `src/utils/math.test.js` (Jest/Vitest)**
|
||||
```javascript
|
||||
import { describe, test, expect } from '@jest/globals';
|
||||
import { add, divide } from './math';
|
||||
|
||||
describe('Math Utils', () => {
|
||||
describe('add()', () => {
|
||||
test('두 양수를 더한다', () => {
|
||||
expect(add(2, 3)).toBe(5);
|
||||
});
|
||||
|
||||
test('음수를 처리한다', () => {
|
||||
expect(add(-5, 3)).toBe(-2);
|
||||
});
|
||||
|
||||
test('0을 처리한다', () => {
|
||||
expect(add(0, 0)).toBe(0);
|
||||
});
|
||||
|
||||
test('소수점을 처리한다', () => {
|
||||
expect(add(0.1, 0.2)).toBeCloseTo(0.3);
|
||||
});
|
||||
|
||||
test('매우 큰 수를 처리한다', () => {
|
||||
expect(add(1e10, 1e10)).toBe(2e10);
|
||||
});
|
||||
});
|
||||
|
||||
describe('divide()', () => {
|
||||
test('정상적인 나눗셈을 수행한다', () => {
|
||||
expect(divide(10, 2)).toBe(5);
|
||||
});
|
||||
|
||||
test('소수 결과를 반환한다', () => {
|
||||
expect(divide(7, 2)).toBe(3.5);
|
||||
});
|
||||
|
||||
test('0으로 나누면 에러를 던진다', () => {
|
||||
expect(() => divide(10, 0)).toThrow('Division by zero');
|
||||
});
|
||||
|
||||
test('음수 나눗셈을 처리한다', () => {
|
||||
expect(divide(-10, 2)).toBe(-5);
|
||||
});
|
||||
|
||||
test('0을 나누면 0을 반환한다', () => {
|
||||
expect(divide(0, 5)).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### B. 통합 테스트 생성 예시
|
||||
|
||||
**대상: API + Database 통합**
|
||||
```javascript
|
||||
// src/services/userService.integration.test.js
|
||||
import { describe, test, expect, beforeAll, afterAll } from '@jest/globals';
|
||||
import { UserService } from './userService';
|
||||
import { setupTestDatabase, cleanupTestDatabase } from '../test-utils/db';
|
||||
|
||||
describe('UserService Integration Tests', () => {
|
||||
let userService;
|
||||
let testDb;
|
||||
|
||||
beforeAll(async () => {
|
||||
testDb = await setupTestDatabase();
|
||||
userService = new UserService(testDb);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanupTestDatabase(testDb);
|
||||
});
|
||||
|
||||
describe('사용자 생성 및 조회', () => {
|
||||
test('새 사용자를 생성하고 조회할 수 있다', async () => {
|
||||
const userData = {
|
||||
name: '홍길동',
|
||||
email: 'hong@test.com'
|
||||
};
|
||||
|
||||
const created = await userService.createUser(userData);
|
||||
expect(created).toHaveProperty('id');
|
||||
expect(created.name).toBe(userData.name);
|
||||
|
||||
const found = await userService.findById(created.id);
|
||||
expect(found).toEqual(created);
|
||||
});
|
||||
|
||||
test('중복 이메일은 거부된다', async () => {
|
||||
await userService.createUser({ name: 'A', email: 'dup@test.com' });
|
||||
|
||||
await expect(
|
||||
userService.createUser({ name: 'B', email: 'dup@test.com' })
|
||||
).rejects.toThrow('Email already exists');
|
||||
});
|
||||
});
|
||||
|
||||
describe('사용자 업데이트', () => {
|
||||
test('사용자 정보를 수정할 수 있다', async () => {
|
||||
const user = await userService.createUser({
|
||||
name: '김철수',
|
||||
email: 'kim@test.com'
|
||||
});
|
||||
|
||||
const updated = await userService.updateUser(user.id, {
|
||||
name: '김영희'
|
||||
});
|
||||
|
||||
expect(updated.name).toBe('김영희');
|
||||
expect(updated.email).toBe('kim@test.com');
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### C. E2E 테스트 생성 예시 (Playwright)
|
||||
|
||||
**대상: 로그인 플로우**
|
||||
```javascript
|
||||
// e2e/login.spec.js
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('로그인 플로우', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('http://localhost:3000');
|
||||
});
|
||||
|
||||
test('성공적인 로그인', async ({ page }) => {
|
||||
// 로그인 페이지로 이동
|
||||
await page.click('text=로그인');
|
||||
await expect(page).toHaveURL(/.*login/);
|
||||
|
||||
// 폼 작성
|
||||
await page.fill('input[name="email"]', 'test@example.com');
|
||||
await page.fill('input[name="password"]', 'password123');
|
||||
|
||||
// 제출
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// 대시보드로 리다이렉트 확인
|
||||
await expect(page).toHaveURL(/.*dashboard/);
|
||||
await expect(page.locator('h1')).toContainText('환영합니다');
|
||||
});
|
||||
|
||||
test('잘못된 비밀번호 에러 처리', async ({ page }) => {
|
||||
await page.click('text=로그인');
|
||||
await page.fill('input[name="email"]', 'test@example.com');
|
||||
await page.fill('input[name="password"]', 'wrongpassword');
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// 에러 메시지 확인
|
||||
await expect(page.locator('.error-message'))
|
||||
.toContainText('비밀번호가 올바르지 않습니다');
|
||||
});
|
||||
|
||||
test('이메일 유효성 검사', async ({ page }) => {
|
||||
await page.click('text=로그인');
|
||||
await page.fill('input[name="email"]', 'invalid-email');
|
||||
await page.fill('input[name="password"]', 'password123');
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// HTML5 validation 또는 커스텀 에러
|
||||
const emailInput = page.locator('input[name="email"]');
|
||||
await expect(emailInput).toHaveAttribute('aria-invalid', 'true');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### React 컴포넌트 테스트 예시
|
||||
|
||||
```javascript
|
||||
// components/Button.test.tsx
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { describe, test, expect, vi } from 'vitest';
|
||||
import Button from './Button';
|
||||
|
||||
describe('Button 컴포넌트', () => {
|
||||
test('텍스트를 올바르게 렌더링한다', () => {
|
||||
render(<Button>클릭</Button>);
|
||||
expect(screen.getByRole('button')).toHaveTextContent('클릭');
|
||||
});
|
||||
|
||||
test('클릭 이벤트를 처리한다', () => {
|
||||
const handleClick = vi.fn();
|
||||
render(<Button onClick={handleClick}>클릭</Button>);
|
||||
|
||||
fireEvent.click(screen.getByRole('button'));
|
||||
expect(handleClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('disabled 상태를 처리한다', () => {
|
||||
render(<Button disabled>클릭</Button>);
|
||||
expect(screen.getByRole('button')).toBeDisabled();
|
||||
});
|
||||
|
||||
test('variant prop에 따라 올바른 클래스를 적용한다', () => {
|
||||
const { rerender } = render(<Button variant="primary">클릭</Button>);
|
||||
expect(screen.getByRole('button')).toHaveClass('btn-primary');
|
||||
|
||||
rerender(<Button variant="secondary">클릭</Button>);
|
||||
expect(screen.getByRole('button')).toHaveClass('btn-secondary');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. 테스트 파일 위치 결정
|
||||
|
||||
프로젝트 구조에 맞게 테스트 파일 저장 위치 결정:
|
||||
|
||||
**옵션 1: 같은 폴더** (권장)
|
||||
```
|
||||
src/utils/
|
||||
├── math.js
|
||||
└── math.test.js
|
||||
```
|
||||
|
||||
**옵션 2: __tests__ 폴더**
|
||||
```
|
||||
src/utils/
|
||||
├── math.js
|
||||
└── __tests__/
|
||||
└── math.test.js
|
||||
```
|
||||
|
||||
**옵션 3: 별도 tests 폴더**
|
||||
```
|
||||
src/utils/math.js
|
||||
tests/unit/utils/math.test.js
|
||||
```
|
||||
|
||||
**E2E 테스트:**
|
||||
```
|
||||
e2e/
|
||||
├── login.spec.js
|
||||
└── signup.spec.js
|
||||
```
|
||||
|
||||
사용자에게 선호하는 위치를 물어보거나, 기존 프로젝트 패턴을 따르세요.
|
||||
|
||||
### 7. 테스트 파일 생성
|
||||
|
||||
Write 도구를 사용하여 생성된 테스트 코드를 파일로 저장:
|
||||
- 적절한 경로에 `.test.js`, `.spec.js` 등의 확장자로 저장
|
||||
- 파일 생성 완료를 사용자에게 알리기
|
||||
|
||||
### 8. 테스트 실행
|
||||
|
||||
생성한 테스트를 자동으로 실행:
|
||||
|
||||
#### A. 테스트 명령어 결정
|
||||
|
||||
`package.json`의 scripts 확인:
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"test:unit": "vitest run",
|
||||
"test:e2e": "playwright test"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### B. 적절한 명령어 실행
|
||||
|
||||
**단위/통합 테스트:**
|
||||
```bash
|
||||
npm test -- [테스트파일경로]
|
||||
# 또는
|
||||
npx jest src/utils/math.test.js
|
||||
# 또는
|
||||
npx vitest run src/utils/math.test.js
|
||||
```
|
||||
|
||||
**E2E 테스트:**
|
||||
```bash
|
||||
npm run test:e2e
|
||||
# 또는
|
||||
npx playwright test e2e/login.spec.js
|
||||
```
|
||||
|
||||
**커버리지 포함:**
|
||||
```bash
|
||||
npm test -- --coverage
|
||||
```
|
||||
|
||||
Bash 도구를 사용하여 테스트 실행하고 결과를 캡처하세요.
|
||||
|
||||
### 9. 결과 상세 리포트 생성
|
||||
|
||||
테스트 실행 결과를 분석하여 사용자에게 상세한 리포트를 제공:
|
||||
|
||||
---
|
||||
|
||||
#### 리포트 형식:
|
||||
|
||||
```markdown
|
||||
# 🧪 테스트 결과 리포트
|
||||
|
||||
## 📋 테스트 정보
|
||||
|
||||
- **대상 파일**: src/utils/math.js
|
||||
- **테스트 파일**: src/utils/math.test.js
|
||||
- **테스트 유형**: 단위 테스트 (Unit Test)
|
||||
- **프레임워크**: Jest 29.5.0
|
||||
- **실행 시간**: 2024-11-14 14:30:25
|
||||
|
||||
---
|
||||
|
||||
## 📊 전체 결과
|
||||
|
||||
✅ **통과**: 9개
|
||||
❌ **실패**: 1개
|
||||
⏭️ **스킵**: 0개
|
||||
|
||||
**성공률**: 90% (9/10)
|
||||
|
||||
---
|
||||
|
||||
## 🔍 상세 테스트 케이스
|
||||
|
||||
### ✅ add() 함수 (5/5 통과)
|
||||
|
||||
#### [PASS] 두 양수를 더한다
|
||||
- **입력**: add(2, 3)
|
||||
- **예상**: 5
|
||||
- **결과**: 5 ✓
|
||||
- **테스트 항목**: 기본 덧셈 연산
|
||||
|
||||
#### [PASS] 음수를 처리한다
|
||||
- **입력**: add(-5, 3)
|
||||
- **예상**: -2
|
||||
- **결과**: -2 ✓
|
||||
- **테스트 항목**: 음수 처리
|
||||
|
||||
#### [PASS] 0을 처리한다
|
||||
- **입력**: add(0, 0)
|
||||
- **예상**: 0
|
||||
- **결과**: 0 ✓
|
||||
- **테스트 항목**: 경계값 (0)
|
||||
|
||||
#### [PASS] 소수점을 처리한다
|
||||
- **입력**: add(0.1, 0.2)
|
||||
- **예상**: ~0.3 (부동소수점 오차 허용)
|
||||
- **결과**: 0.30000000000000004 ✓
|
||||
- **테스트 항목**: 부동소수점 연산
|
||||
|
||||
#### [PASS] 매우 큰 수를 처리한다
|
||||
- **입력**: add(1e10, 1e10)
|
||||
- **예상**: 2e10
|
||||
- **결과**: 20000000000 ✓
|
||||
- **테스트 항목**: 큰 수 처리
|
||||
|
||||
---
|
||||
|
||||
### ⚠️ divide() 함수 (4/5 통과, 1개 실패)
|
||||
|
||||
#### [PASS] 정상적인 나눗셈을 수행한다
|
||||
- **입력**: divide(10, 2)
|
||||
- **예상**: 5
|
||||
- **결과**: 5 ✓
|
||||
- **테스트 항목**: 기본 나눗셈
|
||||
|
||||
#### [PASS] 소수 결과를 반환한다
|
||||
- **입력**: divide(7, 2)
|
||||
- **예상**: 3.5
|
||||
- **결과**: 3.5 ✓
|
||||
- **테스트 항목**: 소수 결과
|
||||
|
||||
#### [FAIL] 0으로 나누면 에러를 던진다 ❌
|
||||
- **입력**: divide(10, 0)
|
||||
- **예상**: Error('Division by zero')
|
||||
- **실제 결과**: Infinity
|
||||
- **테스트 항목**: 에러 핸들링 (0으로 나누기)
|
||||
- **실패 원인**: 함수가 에러를 던지지 않고 Infinity를 반환함
|
||||
|
||||
**스택 트레이스:**
|
||||
```
|
||||
Error: Expected function to throw an error, but it returned Infinity
|
||||
at Object.<anonymous> (src/utils/math.test.js:32:7)
|
||||
```
|
||||
|
||||
**수정 제안:**
|
||||
```javascript
|
||||
export function divide(a, b) {
|
||||
if (b === 0) {
|
||||
throw new Error('Division by zero');
|
||||
}
|
||||
return a / b;
|
||||
}
|
||||
```
|
||||
|
||||
#### [PASS] 음수 나눗셈을 처리한다
|
||||
- **입력**: divide(-10, 2)
|
||||
- **예상**: -5
|
||||
- **결과**: -5 ✓
|
||||
- **테스트 항목**: 음수 처리
|
||||
|
||||
#### [PASS] 0을 나누면 0을 반환한다
|
||||
- **입력**: divide(0, 5)
|
||||
- **예상**: 0
|
||||
- **결과**: 0 ✓
|
||||
- **테스트 항목**: 0을 피제수로 사용
|
||||
|
||||
---
|
||||
|
||||
## 📈 커버리지 리포트
|
||||
|
||||
| 항목 | 비율 | 커버된 라인/전체 라인 |
|
||||
|------|------|----------------------|
|
||||
| **Statements** | 95% | 19/20 |
|
||||
| **Branches** | 87.5% | 7/8 |
|
||||
| **Functions** | 100% | 2/2 |
|
||||
| **Lines** | 95% | 19/20 |
|
||||
|
||||
### 커버되지 않은 코드:
|
||||
|
||||
**라인 15**: `throw new Error('Division by zero')`
|
||||
- 이 라인이 실행되지 않음 (테스트 실패와 연관)
|
||||
|
||||
---
|
||||
|
||||
## ✅ 테스트한 주요 시나리오
|
||||
|
||||
### 1. 정상 입력값 처리
|
||||
- ✅ 양수 연산
|
||||
- ✅ 기본 계산
|
||||
|
||||
### 2. 경계값 테스트
|
||||
- ✅ 0 처리
|
||||
- ✅ 음수 처리
|
||||
- ✅ 매우 큰 수 (1e10)
|
||||
- ✅ 소수점 (0.1, 0.2)
|
||||
|
||||
### 3. 에러 핸들링
|
||||
- ❌ 0으로 나누기 (수정 필요!)
|
||||
|
||||
### 4. 특수 케이스
|
||||
- ✅ 부동소수점 정밀도
|
||||
- ✅ 음수 결과
|
||||
|
||||
---
|
||||
|
||||
## 💡 권장 사항
|
||||
|
||||
### 🔴 즉시 수정 필요
|
||||
|
||||
1. **divide() 함수의 0으로 나누기 처리**
|
||||
- 현재: Infinity 반환
|
||||
- 기대: Error 발생
|
||||
- 우선순위: 높음
|
||||
|
||||
### 🟡 개선 권장
|
||||
|
||||
1. **추가 테스트 케이스**
|
||||
- `add()`: NaN, null, undefined 입력 처리
|
||||
- `divide()`: Infinity 입력 처리
|
||||
- 타입 검증 (문자열 입력 등)
|
||||
|
||||
2. **성능 테스트**
|
||||
- 대량 연산 테스트 추가
|
||||
- 메모리 사용량 확인
|
||||
|
||||
3. **문서화**
|
||||
- JSDoc 주석 추가
|
||||
- 사용 예시 추가
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ 성능 정보
|
||||
|
||||
- **총 실행 시간**: 1.234초
|
||||
- **평균 테스트 시간**: 0.123초
|
||||
- **가장 느린 테스트**: divide() 음수 나눗셈 (0.245초)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 다음 단계
|
||||
|
||||
1. ❌ **실패한 테스트 수정**
|
||||
```bash
|
||||
# divide 함수 수정 후 재실행:
|
||||
npm test src/utils/math.test.js
|
||||
```
|
||||
|
||||
2. 📝 **추가 테스트 작성**
|
||||
- 엣지 케이스 커버리지 향상
|
||||
- 타입 검증 테스트 추가
|
||||
|
||||
3. 🚀 **CI/CD 통합**
|
||||
- GitHub Actions에 테스트 추가
|
||||
- PR 시 자동 테스트 실행
|
||||
|
||||
---
|
||||
|
||||
모든 테스트가 통과하도록 코드를 수정해주세요! 💪
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 10. 추가 기능 (선택적)
|
||||
|
||||
#### A. 자동 수정 제안
|
||||
실패한 테스트에 대해 코드 수정 제안:
|
||||
- 문제 원인 분석
|
||||
- 수정 코드 예시
|
||||
- 사용자가 원하면 자동 수정
|
||||
|
||||
#### B. 테스트 커버리지 개선
|
||||
```
|
||||
📊 커버리지 개선 제안:
|
||||
|
||||
현재: 87.5%
|
||||
목표: 95%+
|
||||
|
||||
추가가 필요한 테스트:
|
||||
1. validateEmail() - 특수문자 이메일 (@, +, . 포함)
|
||||
2. parseJSON() - 잘못된 JSON 형식 처리
|
||||
3. formatDate() - 타임존 처리
|
||||
```
|
||||
|
||||
#### C. 스냅샷 테스트 (React/Vue)
|
||||
```javascript
|
||||
test('컴포넌트 렌더링 스냅샷', () => {
|
||||
const { container } = render(<Button>클릭</Button>);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
```
|
||||
|
||||
## Important Notes:
|
||||
|
||||
### 테스트 작성 원칙
|
||||
- **AAA 패턴**: Arrange (준비), Act (실행), Assert (검증)
|
||||
- **한 테스트는 한 가지만**: 테스트당 하나의 검증 항목
|
||||
- **명확한 테스트 이름**: 무엇을 테스트하는지 한국어로 명확히
|
||||
- **독립성**: 테스트 간 의존성 없이 독립 실행 가능
|
||||
|
||||
### 커버리지 목표
|
||||
- **Statements**: 80% 이상
|
||||
- **Branches**: 75% 이상
|
||||
- **Functions**: 100% (모든 함수 테스트)
|
||||
|
||||
### 사용자 경험
|
||||
- 한국어로 친절하게 설명
|
||||
- 실패 원인과 해결 방법 명확히 제시
|
||||
- 시각적으로 보기 좋은 리포트 (이모지, 테이블 활용)
|
||||
- 테스트 결과를 상세히 분석하여 제공
|
||||
|
||||
### 에러 처리
|
||||
- 테스트 프레임워크 없으면 설치 가이드
|
||||
- 테스트 실행 실패 시 원인 분석
|
||||
- 권한 문제, 환경 문제 등 친절히 안내
|
||||
45
plugin.lock.json
Normal file
45
plugin.lock.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||
"pluginId": "gh:lightsoft-dev/claude-plugin-for-dev:test-generator",
|
||||
"normalized": {
|
||||
"repo": null,
|
||||
"ref": "refs/tags/v20251128.0",
|
||||
"commit": "0ffe769dce985fe4d1fd26bccacc57c1fb197b97",
|
||||
"treeHash": "b2e52f82e4b8700b52120d68d316f435bf9a4cd1e642a3b6775e157efa12d8cf",
|
||||
"generatedAt": "2025-11-28T10:20:19.928297Z",
|
||||
"toolVersion": "publish_plugins.py@0.2.0"
|
||||
},
|
||||
"origin": {
|
||||
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||
"branch": "master",
|
||||
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||
},
|
||||
"manifest": {
|
||||
"name": "test-generator",
|
||||
"description": "Automatically generate and run tests with detailed reports",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"content": {
|
||||
"files": [
|
||||
{
|
||||
"path": "README.md",
|
||||
"sha256": "9a321086f1788e6ece9fa6c55db7d360ba3f69ce61f92fe32cb944a64430271b"
|
||||
},
|
||||
{
|
||||
"path": ".claude-plugin/plugin.json",
|
||||
"sha256": "7d592c6c0e414cd989ebe3ed981fa65041e167c465fd54aa8965e8c1dca8473f"
|
||||
},
|
||||
{
|
||||
"path": "commands/test.md",
|
||||
"sha256": "247c3da79f6cb11cdd36633832e34818b971ba1e972d663f68b7b96073138d3e"
|
||||
}
|
||||
],
|
||||
"dirSha256": "b2e52f82e4b8700b52120d68d316f435bf9a4cd1e642a3b6775e157efa12d8cf"
|
||||
},
|
||||
"security": {
|
||||
"scannedAt": null,
|
||||
"scannerVersion": null,
|
||||
"flags": []
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user