关于 testing-best-practices
这项测试技能帮助开发者在 Playwright、集成测试和单元测试之间做选择,并规划测试数据。它说明如何在隔离且会自动删除的 Neon 分支上运行测试。
主要功能
- 01测试类型选择指南
- 02Playwright、集成和单元测试模式
- 03使用临时 Neon 分支运行测试
- 04按测试套件隔离数据
- 05调试命令与测试产物说明
适用场景
- 01为功能选择合适的测试层级
- 02在隔离的数据库状态上运行测试套件
- 03排查 Playwright 或单元测试失败
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ andrelandgraf/ fullstackrecipes --skill testing-best-practices安装后在 Claude Code 中输入/testing-best-practices确认已加载。
详细介绍
测试最佳实践
选择合适的测试类型,为每个测试套件隔离数据,并在临时 Neon 分支上运行测试。
前置条件
请先完成以下设置指南:
- 使用 Playwright 进行浏览器测试
- 集成测试
- 使用 Bun 进行单元测试
选择测试类型
问问自己“用户会如何验证此功能正常运行?”,然后选择适用范围内最高的测试层级:
- Playwright(默认)——UI 交互、视觉反馈、表单验证、多步骤流程、受保护的路由、无障碍功能。
- 集成测试——API 响应(状态码、JSON 结构)、操作后的数据库状态、不涉及 UI 的服务端逻辑,或 Playwright 测试过慢/过于复杂时。
- 单元测试——包含复杂逻辑或许多边界情况的纯函数,或没有外部依赖的类型收窄/断言。
运行测试
所有测试都在一个隔离的、仅包含 schema 的 Neon 分支上运行,该分支会在 1 小时后自动删除。
bun run test # all tests
bun run test:playwright # browser only
bun run test:integration # integration only
bun run test:unit # unit only
文件夹结构
单元测试与被测代码放在一起;Playwright 测试和集成测试位于 tests/ 下。
src/lib/<domain>/<file>.test.ts # unit (co-located)
tests/integration/<feature>.test.ts
tests/playwright/<feature>.spec.ts
tests/playwright/lib/ # Playwright helpers
编写测试
Playwright 测试文件:
import { test, expect } from "@playwright/test";
test.describe("Feature Name", () => {
test("should do expected behavior", async ({ page }) => {
await page.goto("/feature");
});
});
集成测试——直接导入路由处理程序,而不是通过 HTTP 调用:
import { describe, it, expect } from "bun:test";
import { GET } from "@/app/api/feature/route";
describe("GET /api/feature", () => {
it("returns expected response", async () => {
const response = await GET();
expect(response.status).toBe(200);
const data = await response.json();
expect(data.value).toBeDefined();
});
});
单元测试(与被测代码放在一起):
import { describe, it, expect } from "bun:test";
import { myFunction } from "./my-file";
describe("myFunction", () => {
it("returns expected value", () => {
expect(myFunction()).toBe("expected");
});
});
测试数据隔离
测试会并行使用共享分支,因此每个测试套件都必须拥有自己的数据。为每个测试文件生成唯一用户(例如 auth-test-${uuid}@example.com),避免共享资源,并依靠分支的 TTL 进行清理——绝不要假设其他测试中的数据存在。
const testUser = await createTestUser({
email: `auth-test-${uuid}@example.com`,
});
常见模式
// Protected route (Playwright)
test("redirects unauthenticated user", async ({ page }) => {
await page.goto("/protected-page");
await expect(page).toHaveURL(/sign-in/);
});
// Error state (Playwright)
test("shows error for invalid input", async ({ page }) => {
await page.goto("/form");
await page.getByRole("button", { name: /submit/i }).click();
await expect(page.getByText(/error|required/i)).toBeVisible({
timeout: 5000,
});
});
调试
bunx playwright test --headed # watch the browser
bunx playwright test --debug # step through
bunx playwright show-report # HTML report
bun test --only "test name" # run a single test
bun test --watch # re-run on change
Playwright 运行失败时,会将屏幕截图和跟踪记录保存到 test-results/——CI 失败时请检查此目录。
评论
支持 Markdown