柳嘉希

硕士研究生毕业生

软件工程师 | 可扩展的API · 网络爬虫 · 数据集成 · Vibe代码清理专家

Jest 与 Supertest 复习:单元测试、Mock、异步断言和 API 集成测试

Jest 适合测试函数、服务层、React 组件和异步逻辑。Supertest 则专门用于测试 HTTP 接口。

Jest 断言

常用断言:

expect(value).toBe(5);
expect(obj).toEqual({ id: 1 });
expect(value).toBeTruthy();
expect(arr).toContain("x");
expect(fn).toThrow(/error/);

浮点数不要直接用 toBe

expect(0.1 + 0.2).toBeCloseTo(0.3);

单元测试

业务函数:

export function applyDiscount(price: number, discount: number) {
  if (discount < 0 || discount > 1) return price;
  return price * (1 - discount);
}

测试:

test("calculates discount", () => {
  expect(applyDiscount(100, 0.2)).toBe(80);
});
 
test("returns original price for invalid discount", () => {
  expect(applyDiscount(100, 1.5)).toBe(100);
});

Mock 外部请求

Mock 的目的不是“假装测试通过”,而是隔离外部依赖,让测试只关注当前逻辑。

jest.mock("axios");
const mockedAxios = axios as jest.Mocked<typeof axios>;
 
mockedAxios.get.mockResolvedValueOnce({
  data: { id: 1, name: "Jesse" },
});
 
await expect(getUser(1)).resolves.toEqual({ id: 1, name: "Jesse" });
expect(mockedAxios.get).toHaveBeenCalledWith("/users/1");

常见 Mock 对象:

  • 网络请求
  • 数据库仓库
  • 时间函数
  • 随机数
  • 第三方服务

异步测试

await expect(fetchUser()).resolves.toMatchObject({ id: 1 });
await expect(fetchUser()).rejects.toThrow();

异步测试一定要 returnawait Promise,否则测试可能提前结束。

Supertest 测 API

Supertest 可以不启动真实端口,直接测试 Express/Next/Nest 接口。

const res = await request(app)
  .get("/user/1")
  .query({ detail: "full" })
  .set("Authorization", "Bearer test123");
 
expect(res.statusCode).toBe(200);
expect(res.body).toHaveProperty("id", "1");

POST JSON:

await request(app)
  .post("/login")
  .send({ username: "jesse", password: "123456" })
  .expect(200);

API 测试重点不是只看状态码,还要断言响应结构、错误分支、权限和边界输入。

延伸理解

复习这篇时,不要只记住名词,要把重点放在 Jest 断言、Mock、异步测试、Supertest API 测试和边界条件。这类知识如果只停留在定义层面,很容易在面试或项目中答得很散。更好的理解方式是把它放进一个具体场景:谁在调用它,输入从哪里来,失败后谁负责恢复,数据或状态会不会被重复处理。

  • 测试的目标不是追求覆盖率数字,而是用较低成本锁住关键行为和风险边界。
  • 单元测试、集成测试和 E2E 测试应该分工明确,越靠近 UI 越要少而关键。
  • 高质量测试要避免依赖真实时间、随机数据、网络波动和外部服务状态。

在真实项目中,可以把它当成一个判断框架:先确认输入、约束、失败场景和可观测性,再决定具体工具或写法。 如果一个方案看起来很简单,要继续追问它在规模扩大、权限变化、异常恢复和团队协作下是否仍然成立。

实践检查清单

  • 明确这个知识点在系统中的位置:是开发时约束、运行时能力、基础设施能力,还是协作流程。
  • 写出一个最小可运行例子,并补一个失败例子;只会写 happy path 说明理解还不够稳。
  • 记录常见误用:例如边界条件、权限假设、性能假设、同步/异步差异或环境差异。
  • 把概念和项目经历关联起来:如果面试被追问,可以用自己的项目说明为什么这样选。
  • 最后用一句话总结取舍:它牺牲了什么,换来了什么。

自测问题

  1. 这个主题解决的核心问题是什么?
  2. 如果不用当前方案,还有哪些替代方案?代价是什么?
  3. 最容易出错的边界条件在哪里?
  4. 如何在代码、测试或监控中验证它真的可靠?

项目化应用场景

可以把这类知识放到一个登录或订单接口里理解:单元测试验证纯函数和边界条件,集成测试验证 API 与数据库交互,E2E 测试验证用户关键路径。Mock 应该隔离外部依赖,而不是掩盖真实行为。测试越靠近 UI,成本越高、速度越慢,所以应该覆盖最关键路径,而不是把所有细节都塞进 E2E。

常见误区:

  • 只测成功路径,不测错误路径。
  • Mock 过多导致测试和真实系统脱节。
  • E2E 测试依赖真实时间或不稳定外部服务。