encore-testing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTesting Encore.ts Applications
测试Encore.ts应用
Instructions
操作说明
Encore.ts uses standard TypeScript testing tools. The recommended setup is Vitest.
Encore.ts 使用标准的TypeScript测试工具,推荐使用Vitest进行配置。
Setup Vitest
配置Vitest
bash
npm install -D vitestAdd to :
package.jsonjson
{
"scripts": {
"test": "vitest"
}
}bash
npm install -D vitest在中添加:
package.jsonjson
{
"scripts": {
"test": "vitest"
}
}Test an API Endpoint
测试API端点
typescript
// api.test.ts
import { describe, it, expect } from "vitest";
import { hello } from "./api";
describe("hello endpoint", () => {
it("returns a greeting", async () => {
const response = await hello();
expect(response.message).toBe("Hello, World!");
});
});typescript
// api.test.ts
import { describe, it, expect } from "vitest";
import { hello } from "./api";
describe("hello endpoint", () => {
it("returns a greeting", async () => {
const response = await hello();
expect(response.message).toBe("Hello, World!");
});
});Run Tests
运行测试
bash
undefinedbash
undefinedRun with Encore (recommended - sets up infrastructure)
使用Encore运行(推荐 - 自动搭建基础设施)
encore test
encore test
Or run directly with npm
或直接用npm运行
npm test
Using `encore test` is recommended because it:
- Sets up test databases automatically
- Provides isolated infrastructure per test
- Handles service dependenciesnpm test
推荐使用`encore test`的原因:
- 自动搭建测试数据库
- 为每个测试提供独立的基础设施
- 处理服务依赖Test with Request Parameters
带请求参数的测试
typescript
// api.test.ts
import { describe, it, expect } from "vitest";
import { getUser } from "./api";
describe("getUser endpoint", () => {
it("returns the user by ID", async () => {
const user = await getUser({ id: "123" });
expect(user.id).toBe("123");
expect(user.name).toBeDefined();
});
});typescript
// api.test.ts
import { describe, it, expect } from "vitest";
import { getUser } from "./api";
describe("getUser endpoint", () => {
it("returns the user by ID", async () => {
const user = await getUser({ id: "123" });
expect(user.id).toBe("123");
expect(user.name).toBeDefined();
});
});Test Database Operations
测试数据库操作
Encore provides isolated test databases:
typescript
// user.test.ts
import { describe, it, expect, beforeEach } from "vitest";
import { createUser, getUser, db } from "./user";
describe("user operations", () => {
beforeEach(async () => {
// Clean up before each test
await db.exec`DELETE FROM users`;
});
it("creates and retrieves a user", async () => {
const created = await createUser({ email: "test@example.com", name: "Test" });
const retrieved = await getUser({ id: created.id });
expect(retrieved.email).toBe("test@example.com");
});
});Encore提供独立的测试数据库:
typescript
// user.test.ts
import { describe, it, expect, beforeEach } from "vitest";
import { createUser, getUser, db } from "./user";
describe("user operations", () => {
beforeEach(async () => {
// 每次测试前清理数据
await db.exec`DELETE FROM users`;
});
it("creates and retrieves a user", async () => {
const created = await createUser({ email: "test@example.com", name: "Test" });
const retrieved = await getUser({ id: created.id });
expect(retrieved.email).toBe("test@example.com");
});
});Test Service-to-Service Calls
测试服务间调用
typescript
// order.test.ts
import { describe, it, expect } from "vitest";
import { createOrder } from "./order";
describe("order service", () => {
it("creates an order and notifies user service", async () => {
// Service calls work normally in tests
const order = await createOrder({
userId: "user-123",
items: [{ productId: "prod-1", quantity: 2 }],
});
expect(order.id).toBeDefined();
expect(order.status).toBe("pending");
});
});typescript
// order.test.ts
import { describe, it, expect } from "vitest";
import { createOrder } from "./order";
describe("order service", () => {
it("creates an order and notifies user service", async () => {
// 测试中服务调用可正常工作
const order = await createOrder({
userId: "user-123",
items: [{ productId: "prod-1", quantity: 2 }],
});
expect(order.id).toBeDefined();
expect(order.status).toBe("pending");
});
});Test Error Cases
测试错误场景
typescript
import { describe, it, expect } from "vitest";
import { getUser } from "./api";
import { APIError } from "encore.dev/api";
describe("error handling", () => {
it("throws NotFound for missing user", async () => {
await expect(getUser({ id: "nonexistent" }))
.rejects
.toThrow("user not found");
});
it("throws with correct error code", async () => {
try {
await getUser({ id: "nonexistent" });
} catch (error) {
expect(error).toBeInstanceOf(APIError);
expect((error as APIError).code).toBe("not_found");
}
});
});typescript
import { describe, it, expect } from "vitest";
import { getUser } from "./api";
import { APIError } from "encore.dev/api";
describe("error handling", () => {
it("throws NotFound for missing user", async () => {
await expect(getUser({ id: "nonexistent" }))
.rejects
.toThrow("user not found");
});
it("throws with correct error code", async () => {
try {
await getUser({ id: "nonexistent" });
} catch (error) {
expect(error).toBeInstanceOf(APIError);
expect((error as APIError).code).toBe("not_found");
}
});
});Test Pub/Sub
测试发布/订阅(Pub/Sub)
typescript
// notifications.test.ts
import { describe, it, expect, vi } from "vitest";
import { orderCreated } from "./events";
describe("pub/sub", () => {
it("publishes order created event", async () => {
const messageId = await orderCreated.publish({
orderId: "order-123",
userId: "user-456",
total: 9999,
});
expect(messageId).toBeDefined();
});
});typescript
// notifications.test.ts
import { describe, it, expect, vi } from "vitest";
import { orderCreated } from "./events";
describe("pub/sub", () => {
it("publishes order created event", async () => {
const messageId = await orderCreated.publish({
orderId: "order-123",
userId: "user-456",
total: 9999,
});
expect(messageId).toBeDefined();
});
});Test Cron Jobs
测试定时任务(Cron Jobs)
Test the underlying function, not the cron schedule:
typescript
// cleanup.test.ts
import { describe, it, expect } from "vitest";
import { cleanupExpiredSessions } from "./cleanup";
describe("cleanup job", () => {
it("removes expired sessions", async () => {
// Create some expired sessions first
await createExpiredSession();
// Call the endpoint directly
await cleanupExpiredSessions();
// Verify cleanup happened
const remaining = await countSessions();
expect(remaining).toBe(0);
});
});测试底层功能,而非定时调度:
typescript
// cleanup.test.ts
import { describe, it, expect } from "vitest";
import { cleanupExpiredSessions } from "./cleanup";
describe("cleanup job", () => {
it("removes expired sessions", async () => {
// 先创建一些过期会话
await createExpiredSession();
// 直接调用处理函数
await cleanupExpiredSessions();
// 验证清理完成
const remaining = await countSessions();
expect(remaining).toBe(0);
});
});Mocking External Services
模拟外部服务
typescript
import { describe, it, expect, vi, beforeEach } from "vitest";
import { sendWelcomeEmail } from "./email";
// Mock external API
vi.mock("./external-email-client", () => ({
send: vi.fn().mockResolvedValue({ success: true }),
}));
describe("email service", () => {
it("sends welcome email", async () => {
const result = await sendWelcomeEmail({ userId: "123" });
expect(result.sent).toBe(true);
});
});typescript
import { describe, it, expect, vi, beforeEach } from "vitest";
import { sendWelcomeEmail } from "./email";
// 模拟外部API
vi.mock("./external-email-client", () => ({
send: vi.fn().mockResolvedValue({ success: true }),
}));
describe("email service", () => {
it("sends welcome email", async () => {
const result = await sendWelcomeEmail({ userId: "123" });
expect(result.sent).toBe(true);
});
});Test Configuration
测试配置
Create :
vitest.config.tstypescript
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
environment: "node",
include: ["**/*.test.ts"],
coverage: {
reporter: ["text", "json", "html"],
},
},
});创建:
vitest.config.tstypescript
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
environment: "node",
include: ["**/*.test.ts"],
coverage: {
reporter: ["text", "json", "html"],
},
},
});Guidelines
测试指南
- Use to run tests with infrastructure setup
encore test - Each test file gets an isolated database transaction (rolled back after)
- Test API endpoints by calling them directly as functions
- Service-to-service calls work normally in tests
- Mock external dependencies (third-party APIs, email services, etc.)
- Don't mock Encore infrastructure (databases, Pub/Sub) - use the real thing
- 使用运行测试,自动搭建基础设施
encore test - 每个测试文件拥有独立的数据库事务(测试后自动回滚)
- 通过直接调用函数的方式测试API端点
- 测试中服务间调用可正常工作
- 模拟外部依赖(第三方API、邮件服务等)
- 不要模拟Encore基础设施(数据库、Pub/Sub)- 使用真实组件