cursor-init/.test-rules.md
expressgy 5b0b37ef78 chore: 项目初始化相关配置与文档归档优化
- Prettier 配置迁移为 .prettierrc.cjs,解决 ESM/CJS 兼容问题
- 优化 package.json,补全元信息、整理依赖、完善 Bun 热更新脚本
- 归档项目初始化 PRD 与任务清单到 tasks/archive,并加日期前缀
- 同步代码风格与格式化配置,提升团队协作一致性

归档文件:tasks/archive/20240610-prd-项目初始化.md, tasks/archive/20240610-tasks-prd-项目初始化.md
2025-06-28 02:03:40 +08:00

3.4 KiB
Raw Blame History

Elysia + Vitest 测试用例编写规范

1. 文件结构与命名

  • 每个被测模块应有对应的 xxx.test.ts 文件,放在同目录或 tests/ 下。
  • 测试文件需有文件头注释,说明作者、日期、描述等。

2. 测试用例基本格式

  • 使用 describe 分组,it(或 test)描述单个场景。
  • 每个 it 需有明确的行为描述。

3. 参数传递与类型

  • 明确传递参数类型,推荐用 TypeBox schema 自动推导类型。
  • 测试用例中参数应覆盖正常、异常、边界值。

4. 响应结构与 code 校验

  • 断言 HTTP 状态码(如 200、400、401
  • 断言响应体结构(如 code、message、data类型可用 as any 或 schema 类型断言。

5. 边界与异常测试

  • 必须覆盖参数边界(如最短/最长用户名、最短密码等)。
  • 必须覆盖异常分支如缺少参数、token 错误、未授权等)。

6. 类型安全

  • 推荐用 TypeBox 的 Static<typeof schema> 推导类型,或在测试用例中用 as any 简化断言。
  • 对于复杂响应,可定义类型辅助断言。

7. 断言范围

  • 断言应覆盖HTTP 状态码、响应 code、message、data 字段、关键数据类型。
  • 对于 token、id 等动态值,用 typeof 或正则断言。

8. 其他建议

  • it.only/describe.only 聚焦调试,提交前移除。
  • console.log 输出实际响应,便于排查失败。
  • 每个接口的正常、异常、边界场景都应有测试覆盖。

9. 示例

/**
 * @file        用户登录接口测试
 * @author      hotok
 * @date        2025-06-28
 * @lastEditor  hotok
 * @lastEditTime 2025-06-28
 * @description 覆盖登录接口的正常、异常、边界场景
 */

describe('POST /api/login', () => {
    it('应登录成功并返回token', async () => {
        const res = await app.fetch(
            new Request('http://localhost/api/login', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ username: 'admin', password: '123456' }),
            }),
        );
        const body = (await res.json()) as any;
        expect(res.status).toBe(200);
        expect(body.code).toBe(0);
        expect(typeof body.data.token).toBe('string');
    });

    it('用户名过短应返回400', async () => {
        const res = await app.fetch(
            new Request('http://localhost/api/login', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ username: 'a', password: '123456' }),
            }),
        );
        const body = (await res.json()) as any;
        expect(res.status).toBe(400);
        expect(body.code).toBe(400);
        expect(body.message).toMatch(/用户名长度/);
    });

    it('密码错误应返回400', async () => {
        const res = await app.fetch(
            new Request('http://localhost/api/login', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ username: 'admin', password: 'wrong' }),
            }),
        );
        const body = (await res.json()) as any;
        expect(res.status).toBe(400);
        expect(body.code).toBe(400);
        expect(body.message).toBe('用户名或密码错误');
    });
});