Chapter 08

测试与质量

内置测试运行器、BDD 风格、覆盖率与性能基准——零配置测试体验

deno test:内置测试运行器

Deno 内置完整的测试运行器,无需安装 Jest、Mocha、Vitest 等任何测试框架。只需运行 deno test,它会自动发现所有 *.test.ts*_test.ts*.spec.ts 文件:

# 运行所有测试
deno test

# 运行指定文件
deno test user.test.ts

# 监视模式(文件变更自动重跑)
deno test --watch

# 详细输出
deno test --reporter=verbose

# 并行运行(默认)
deno test --parallel

# 运行匹配名称的测试
deno test --filter "用户创建"

Deno.test():基础用法

// math.test.ts
import { assertEquals, assertThrows } from "jsr:@std/assert";
import { add, divide } from "./math.ts";

// 同步测试
Deno.test("两数相加", () => {
  assertEquals(add(1, 2), 3);
  assertEquals(add(-1, 1), 0);
});

// 异步测试
Deno.test("异步获取用户", async () => {
  const user = await fetchUser(1);
  assertEquals(user.id, 1);
  assertEquals(typeof user.name, "string");
});

// 异常测试
Deno.test("除以零应抛出错误", () => {
  assertThrows(
    () => divide(1, 0),
    Error,
    "除数不能为零"
  );
});

// 带 options 的测试
Deno.test({
  name: "需要网络权限的测试",
  permissions: { net: true },  // 单测试权限控制
  async fn() {
    const res = await fetch("https://api.example.com");
    assertEquals(res.status, 200);
  }
});

// 跳过测试
Deno.test.skip("暂时跳过", () => { /* ... */ });

// 仅运行此测试(调试时有用)
Deno.test.only("只跑这个", () => { /* ... */ });

@std/assert 断言库

断言函数用途
assertEquals(a, b)深度相等断言(对象、数组)
assertStrictEquals(a, b)严格相等(===)
assertNotEquals(a, b)不相等
assertThrows(fn, Err, msg)同步异常断言
assertRejects(fn, Err, msg)异步 Promise reject 断言
assertExists(val)不为 null/undefined
assertMatch(str, regex)正则匹配
assertInstanceOf(val, Type)类型断言
assertArrayIncludes(arr, items)数组包含
unreachable()标记不可达代码

BDD 风格:describe / it

// user.test.ts — BDD 风格(类似 Jest)
import { describe, it, beforeAll, afterAll, beforeEach } from "jsr:@std/testing/bdd";
import { assertEquals, assertExists } from "jsr:@std/assert";

describe("UserService", () => {
  let userService: UserService;

  beforeAll(async () => {
    userService = await UserService.create({ /* db config */ });
  });

  afterAll(async () => {
    await userService.destroy();
  });

  describe("createUser", () => {
    it("成功创建用户", async () => {
      const user = await userService.create({ name: "Alice", email: "a@test.com" });
      assertExists(user.id);
      assertEquals(user.name, "Alice");
    });

    it("重复邮箱应报错", async () => {
      await userService.create({ name: "Bob", email: "b@test.com" });
      await assertRejects(
        () => userService.create({ name: "Bob2", email: "b@test.com" }),
        Error,
        "邮箱已存在"
      );
    });
  });

  describe("getUser", () => {
    it("找不到用户返回 null", async () => {
      const result = await userService.findById(999999);
      assertEquals(result, null);
    });
  });
});

Snapshot 测试

import { assertSnapshot } from "jsr:@std/testing/snapshot";

Deno.test("渲染结果快照", async (t) => {
  const output = renderComponent({ title: "Hello", count: 42 });

  // 第一次运行:生成 __snapshots__/xxx.snap 文件
  // 后续运行:与快照对比
  await assertSnapshot(t, output);
});

# 更新快照
deno test --update-snapshots

测试覆盖率

# 收集覆盖率数据
deno test --coverage=coverage/

# 生成覆盖率报告
deno coverage coverage/

# 生成 lcov 格式(用于 CI 上传)
deno coverage coverage/ --lcov --output=coverage.lcov

# HTML 报告(需要安装 genhtml)
genhtml coverage.lcov --output-directory html-coverage/

deno bench:性能基准测试

Deno 内置了性能基准测试(Benchmark)工具,无需 benchmark.js 等第三方库:

// bench.ts — 性能基准
Deno.bench("JSON.parse vs structuredClone", { group: "clone", baseline: true }, () => {
  const data = { users: [{ id: 1, name: "Alice" }] };
  JSON.parse(JSON.stringify(data));
});

Deno.bench("structuredClone", { group: "clone" }, () => {
  const data = { users: [{ id: 1, name: "Alice" }] };
  structuredClone(data);
});

Deno.bench("SHA-256 哈希", async () => {
  const data = new TextEncoder().encode("hello world");
  await crypto.subtle.digest("SHA-256", data);
});
# 运行基准测试
deno bench bench.ts

# 输出示例:
# benchmark              time/iter (avg)        iter/s
# ---------------------- ---------------  -----------
# JSON.parse vs struct.           312 ns    3,205,125
# structuredClone                 489 ns    2,044,990
# SHA-256 哈希                    4.6 µs      217,391

本章小结:Deno 的内置测试工具链是最完整的——deno test 运行测试,deno bench 做性能基准,deno coverage 生成覆盖率报告,全部开箱即用。BDD 风格(describe/it)通过 @std/testing/bdd 提供,Snapshot 测试通过 @std/testing/snapshot 提供。无需安装和配置任何测试框架——这正是 Deno 工具链一体化的优势所在。