# 测试用例编写指南

本文档旨在为 NStudyPy 项目提供测试编写与执行的规范和最佳实践参考。

## 1. 测试环境与执行

本项目使用 `pytest` 作为测试框架，并通过 `uv` 进行依赖管理和任务执行。

### 执行测试

- **运行所有测试**:
  ```bash
  uv run pytest
  ```

- **运行单个测试文件**:
  ```bash
  uv run pytest tests/test_PyRe.py
  ```

- **运行特定测试函数**:
  ```bash
  uv run pytest tests/test_PyRe.py::test_format_id_card
  ```

- **查看详细输出**:
  ```bash
  uv run pytest -v
  ```

## 2. 测试文件结构

所有的测试代码都应存放在 `tests/` 目录下。

- **命名规范**:
  - 测试文件应以 `test_` 开头（例如 `test_PyRe.py`）。
  - 测试函数应以 `test_` 开头。
  - 测试类应以 `Test` 开头。

## 3. 编写测试用例最佳实践

### 3.1 使用参数化 (Parametrize)

避免为相似的输入编写重复的测试函数，使用 `@pytest.mark.parametrize` 装饰器。这不仅减少了代码冗余，还能清晰地展示测试数据的覆盖范围。

```python
import pytest
from NStudyPy.PyRe import format_id_card

@pytest.mark.parametrize("input_id, expected", [
    ("350524800101001", "350524800101001"), # 正常情况
    ("123", ""),                            # 异常/边界情况
])
def test_format_id_card(input_id, expected):
    assert format_id_card(input_id) == expected
```

### 3.2 显式断言 (Explicit Assertions)

`pytest` 允许直接使用 Python 的标准 `assert` 关键字，这使得代码非常易读且直观。

- **推荐**: `assert result == expected`
- **避免**: `self.assertEqual(result, expected)` (Unittest 风格，除非在迁移旧代码)

### 3.3 测试异常

对于预期会抛出错误的情况，使用 `pytest.raises` 上下文管理器来捕获并验证异常。

```python
def test_input_none_raises_error():
    with pytest.raises(TypeError):
        # 假设该函数在输入 None 时应抛出 TypeError
        format_id_card(None)
```

### 3.4 保持测试独立性 (Isolation)

每个测试用例应该是完全独立的：
- 不依赖于其他测试的执行顺序。
- 不依赖于其他测试产生的数据。
- 不修改全局状态（如果必须修改，请确保在测试结束时恢复，通常通过 fixture 实现）。

### 3.5 使用 Fixtures 管理资源

对于需要重复使用的设置（Setup）和清理（Teardown）逻辑（如准备测试数据、Mock对象、临时文件等），请使用 `pytest.fixture`。

```python
@pytest.fixture
def sample_user():
    return {"name": "Test User", "id": 12345}

def test_user_name(sample_user):
    assert sample_user["name"] == "Test User"
```

## 4. 覆盖率与边界测试

- **边界情况**: 测试空字符串、None、极大值、极小值、非法字符等。
- **正向与反向**: 既要测试“正确输入得到预期结果”，也要测试“错误输入得到预期报错或默认值”。

---
遵循以上规范将有助于保持 NStudyPy 项目代码库的健壮性和可维护性。
