fastpaper-cli 0.3.0

CLI tool for searching, downloading and reading academic papers
Documentation
# 测试

> English: [testing.md]testing.md

## 运行测试

```bash
cargo test                 # 全部(离线运行,无需任何 key)
cargo test --lib           # 仅单元测试
cargo test --test cli      # 仅 CLI 集成测试
```

布局:

- **单元测试**与代码同文件,在各源文件的 `#[cfg(test)]` 模块里(目前约 330 个)。解析器测试用 `include_str!` 加载录制好的 fixture。
- **集成测试**`tests/cli.rs`(目前约 57 个),用 `assert_cmd` 驱动真实二进制,对着本地 mockito server 跑。

## HTTP mock

使用 [mockito](https://docs.rs/mockito)(同步 API)。典型写法:

```rust
let mut server = mockito::Server::new();
let mock = server
    .mock("GET", mockito::Matcher::Regex("pn=10".to_string()))  // 路径+查询串正则
    .match_header("acs-token", "expected-value")                 // 断言请求头
    .with_status(200)
    .with_body(FIXTURE)
    .expect(1)                                                   // 精确调用次数
    .create();
// ... 调用 search(&server.url(), ...) ...
mock.assert();
```

`Matcher::Any` 匹配一切;`.expect(0)` + `.assert()` 可证明某端点**没有**被调用(分页提前停止的测试就靠它)。

## Fixture

- 位置:`tests/fixtures/<source>_search.json`(或 `.xml` / `.html`)。
- 必须是**脱敏后的真实响应**,不能手编 JSON:去掉带签名的 URL 和 `authorization=` 查询串,匿名化日志/请求 ID,删除任何个人信息。
- 保留真实的字段差异(空串、`null`、HTML 标签)——解析器容错测试正是靠这些喂养。

## 真实 API 测试

访问真实服务的测试标记 `#[ignore]`,和其他测试一起放在 `tests/` 下:

```bash
cargo test --test cli -- --ignored     # 手动执行
```

绝不进 CI。失败时,先判断是不是对方限频/风控所致(换个关键词、等一等、重试一次),再当作回归处理。

## 惯例

- 每个测试只测一个行为;测试名描述该行为(`parse_empty_doi_becomes_none`)。
- 设置或删除环境变量的测试用 `serial_test``#[serial]`,避免测试间竞争。
- 新功能的测试必须随同一个 PR 提交。