| name | test-generator |
| description | 生成測試套件。觸發:test、測試、寫測試、coverage、覆蓋率、pytest、unittest、驗證、TG、unit test、整合測試、e2e、static、ruff、mypy、lint。 |
測試生成技能
測試金字塔
/\ E2E (少量)
/--\ Integration (中等)
/----\ Unit (大量)
/------\ Static Analysis (基礎)
靜態分析工具 (Static Analysis)
工具總覽
| 工具 | 用途 | 命令 |
|---|---|---|
| ruff | Linter + Formatter | uv run ruff check src/ |
| mypy | 類型檢查 | uv run mypy src/ --ignore-missing-imports |
| bandit | 安全漏洞掃描 | uv run bandit -r src/ -ll |
| vulture | 死代碼檢測 | uv run vulture src/ --min-confidence 80 |
Bandit 安全掃描
# 只顯示 Medium+ 嚴重度 (推薦)
uv run bandit -r src/ -ll
# 顯示所有問題 (包含 Low)
uv run bandit -r src/ -l
# 常見 nosec 註解
# nosec B110 - 有意的 try_except_pass
# nosec B404 - 有意使用 subprocess
# nosec B603 - 信任的 subprocess 呼叫
# nosec B607 - 信任的部分路徑執行
Vulture 死代碼檢測
# 80% 置信度以上
uv run vulture src/ --min-confidence 80
# 產生 whitelist(排除誤報)
uv run vulture src/ --make-whitelist > vulture_whitelist.py
Ruff 配置 (pyproject.toml)
[tool.ruff]
target-version = "py310"
line-length = 100
[tool.ruff.lint]
select = ["E", "F", "W", "I", "UP", "B", "SIM"]
ignore = ["E501"] # 行長由 formatter 處理
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"] # 允許 re-export
"tests/**" = ["S101"] # 允許 assert
[tool.ruff.format]
quote-style = "double"
Mypy 配置 (pyproject.toml)
[tool.mypy]
python_version = "3.10"
warn_return_any = true
warn_unused_ignores = true
disallow_untyped_defs = true
no_implicit_optional = true
[[tool.mypy.overrides]]
module = ["mcp.*", "docx.*", "PyPDF2.*"]
ignore_missing_imports = true
靜態分析執行流程
# 1. Ruff 自動修復 (先執行)
uv run ruff check src/ --fix --unsafe-fixes
uv run ruff format src/
# 2. Mypy 類型檢查
uv run mypy src/ --ignore-missing-imports
# 3. Bandit 安全掃描
uv run bandit -r src/ -ll
# 4. Vulture 死代碼檢測 (可選)
uv run vulture src/ --min-confidence 80
# 完整一次執行
uv run ruff check src/; uv run mypy src/ --ignore-missing-imports; uv run bandit -r src/ -ll
uv run mypy src/ --ignore-missing-imports
3. 安全掃描 (可選)
uv run bandit -r src/ -ll
### 常見 Mypy 錯誤修復
| 錯誤 | 解法 |
|------|------|
| `no_implicit_optional` | `def foo(x: str = None)` → `def foo(x: Optional[str] = None)` |
| `var-annotated` | `results = []` → `results: List[T] = []` |
| `arg-type` | 檢查 Optional 是否需要 `or default` |
| `return-value` | 確保函數返回類型與聲明一致 |
| `call-overload` | 使用 `# type: ignore[call-overload]` |
---
## Python 測試工具
| 層級 | 工具 | 配置 |
|------|------|------|
| Static | `mypy`, `ruff`, `bandit` | pyproject.toml |
| Unit | `pytest` | tests/unit/ |
| Integration | `pytest` + `httpx` | tests/integration/ |
| E2E | `playwright` | tests/e2e/ |
| Coverage | `pytest-cov` | 目標 ≥80% |
---
## 目錄結構
tests/ ├── conftest.py # 共用 fixtures ├── unit/ # 單元測試 │ └── test_domain/ ├── integration/ # 整合測試 │ └── test_api/ └── e2e/ # 端對端測試
---
## 單元測試模式
### 必須涵蓋
1. **Happy Path** - 正常流程
2. **Edge Cases** - 邊界條件
3. **Error Handling** - 錯誤處理
4. **Null/None** - 空值處理
### 範例結構
```python
class TestUser:
def test_create_user_valid(self): # Happy path
...
def test_create_user_min_length(self): # Edge case
...
def test_create_user_empty_raises(self): # Error handling
with pytest.raises(ValidationError):
...
@pytest.mark.parametrize(...) # 多參數測試
def test_variations(self, input, expected):
...
整合測試模式
API 測試
@pytest.mark.integration
async def test_create_endpoint(async_client):
response = await async_client.post("/api/users", json={...})
assert response.status_code == 201
DB 測試
@pytest.mark.integration
async def test_save_and_retrieve(repository, db_session):
saved = await repository.save(entity)
retrieved = await repository.get_by_id(saved.id)
assert retrieved is not None
常用 Fixtures
# conftest.py
@pytest.fixture
def sample_user():
return User(name="Test", email="test@test.com")
@pytest_asyncio.fixture
async def async_client():
async with AsyncClient(app=app) as client:
yield client
@pytest_asyncio.fixture
async def db_session():
async with AsyncSession() as session:
yield session
await session.rollback()
執行命令
# 靜態分析
mypy src/
ruff check src/
# 單元測試
pytest tests/unit -v
# 整合測試
pytest tests/integration -v -m integration
# 全部 + 覆蓋率
pytest --cov=src --cov-report=term-missing --cov-fail-under=80
# E2E
pytest tests/e2e -v --headed # 顯示瀏覽器
pyproject.toml 配置
[tool.pytest.ini_options]
testpaths = ["tests"]
markers = ["unit", "integration", "e2e", "slow"]
asyncio_mode = "auto"
[tool.coverage.run]
source = ["src"]
branch = true
omit = ["tests/*", "*/__init__.py"]
[tool.coverage.report]
fail_under = 80
show_missing = true
生成 Checklist
- 確認測試目錄結構
- Happy path 測試
- Edge cases 測試
- Error handling 測試
- Fixtures 設定
- CI workflow 整合
- 覆蓋率 ≥ 80%
相關技能
code-reviewer- 審查測試品質