testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Testing conventions and in-memory databases

测试规范与内存数据库

When to use: Writing or debugging tests, choosing unit vs integration style, Postgres/ClickHouse tests, regenerating ClickHouse test schema, or exporting test helpers from packages without pulling test code into production bundles.
适用场景: 编写或调试测试、选择单元测试与集成测试类型、Postgres/ClickHouse测试、重新生成ClickHouse测试架构,或者从包中导出测试工具同时避免将测试代码引入生产包。

Package exports (test code isolation)

包导出(测试代码隔离)

Test utilities (fakes, in-memory DB helpers, fixtures) must not be exported from a package’s main entry (
src/index.ts
).
  • Never re-export from
    ./test/
    or
    ./testing/
    in the main
    src/index.ts
  • To expose test helpers, add a
    /testing
    subpath
    in
    package.json
    exports
    :
json
{
  "exports": {
    ".": "./src/index.ts",
    "./testing": "./src/testing/my-test-helpers.ts"
  }
}
  • Consumers:
    import { Fake } from "@platform/my-package/testing"
  • Biome
    noRestrictedImports
    blocks test paths in production source; tsdown fails the build if test code is resolved from prod entry points
测试工具(模拟对象、内存数据库助手、测试夹具)绝对不能从包的主入口(
src/index.ts
)导出。
  • 绝对不要在主入口
    src/index.ts
    中重新导出
    ./test/
    ./testing/
    下的内容
  • 如需暴露测试助手,在
    package.json
    exports
    中添加**
    /testing
    子路径**:
json
{
  "exports": {
    ".": "./src/index.ts",
    "./testing": "./src/testing/my-test-helpers.ts"
  }
}
  • 消费者使用方式:
    import { Fake } from "@platform/my-package/testing"
  • Biome的
    noRestrictedImports
    规则会阻止生产代码引入测试路径;若生产入口解析到测试代码,tsdown会使构建失败

Conventions

测试规范

  • Shared default environment: Node with globals enabled (
    packages/vitest-config/index.ts
    )
  • Write tests, mostly e2e, some unit tests when logic is complex
  • Unit tests: domain entities/use-cases/policies with fakes
  • Contract tests: adapter compliance against domain ports
  • Integration tests: infra-backed tests for Postgres/ClickHouse/Redis/BullMQ/object storage
  • End-to-end tests: ingest boundary to query boundary across organization scoping
  • Keep tests deterministic and isolated
  • Prefer package-local runs during iteration; run full monorepo tests before PR
  • 共享默认环境:启用全局变量的Node环境(
    packages/vitest-config/index.ts
  • 编写测试时,以端到端测试为主,当逻辑复杂时编写单元测试
  • 单元测试:针对领域实体/用例/策略,使用模拟对象
  • 契约测试:验证适配器是否符合领域端口要求
  • 集成测试:针对Postgres/ClickHouse/Redis/BullMQ/对象存储的基础设施测试
  • 端到端测试:覆盖从数据摄入边界到查询边界的全流程,包含组织范围限定
  • 保持测试的确定性与隔离性
  • 迭代期间优先运行包本地测试;提交PR前运行完整的单仓库测试

Database testing (in-memory)

数据库测试(内存型)

Always use in-memory databases for tests. Do not use
vi.mock
/
vi.fn
to mock repository methods and do not require running database servers. The project provides embedded, in-process database engines that run the real SQL against the real schema:
  • ClickHouse → chdb (
    chdb
    package): An in-process ClickHouse engine via
    @platform/testkit
    .
  • Postgres → PGlite (
    @electric-sql/pglite
    ): An in-process Postgres via WASM via
    @platform/testkit
    .
测试必须使用内存数据库。不要使用
vi.mock
/
vi.fn
来模拟仓库方法,也不需要运行外部数据库服务器。项目提供了嵌入式、进程内的数据库引擎,可基于真实架构运行真实SQL:
  • ClickHouse → chdb
    chdb
    包):通过
    @platform/testkit
    提供的进程内ClickHouse引擎。
  • Postgres → PGlite
    @electric-sql/pglite
    ):通过
    @platform/testkit
    提供的基于WASM的进程内Postgres。

Postgres test setup (
@platform/testkit
)

Postgres测试配置(
@platform/testkit

typescript
import { setupTestPostgres } from "@platform/testkit"
import { beforeAll, describe, it } from "vitest"

const pg = setupTestPostgres()

describe("MyRepository", () => {
  it("does something", async () => {
    // pg.postgresDb is a real Drizzle instance backed by PGlite in-memory
    // pg.db is the lower-level Drizzle/PGlite instance for direct queries
  })
})
setupTestPostgres()
registers vitest hooks automatically:
  • beforeAll: creates a PGlite instance, creates the
    latitude_app
    role, and runs all Drizzle migrations
  • afterAll: closes the PGlite connection
typescript
import { setupTestPostgres } from "@platform/testkit"
import { beforeAll, describe, it } from "vitest"

const pg = setupTestPostgres()

describe("MyRepository", () => {
  it("does something", async () => {
    // pg.postgresDb是基于内存PGlite的真实Drizzle实例
    // pg.db是用于直接查询的底层Drizzle/PGlite实例
  })
})
setupTestPostgres()
会自动注册vitest钩子:
  • beforeAll:创建PGlite实例、创建
    latitude_app
    角色,并运行所有Drizzle迁移
  • afterAll:关闭PGlite连接

ClickHouse test setup (
@platform/testkit
)

ClickHouse测试配置(
@platform/testkit

typescript
import { setupTestClickHouse } from "@platform/testkit"
import { beforeAll, describe, it } from "vitest"

const ch = setupTestClickHouse()

describe("MyRepository", () => {
  let repo: ReturnType<typeof createMyRepository>

  beforeAll(() => {
    repo = createMyRepository(ch.client)
  })

  it("does something", async () => {
    // ch.client is a real ClickHouseClient backed by chdb in-memory
  })
})
setupTestClickHouse()
registers vitest hooks automatically:
  • beforeAll: creates a chdb session and loads the schema from
    schema.sql
  • beforeEach: truncates all tables for test isolation
  • afterAll: destroys the session and cleans up temp files
After new ClickHouse migrations, regenerate the in-memory test schema (only if the user asked you to run migration-related commands — see database-clickhouse-weaviate):
bash
pnpm --filter @platform/db-clickhouse ch:schema:dump
typescript
import { setupTestClickHouse } from "@platform/testkit"
import { beforeAll, describe, it } from "vitest"

const ch = setupTestClickHouse()

describe("MyRepository", () => {
  let repo: ReturnType<typeof createMyRepository>

  beforeAll(() => {
    repo = createMyRepository(ch.client)
  })

  it("does something", async () => {
    // ch.client是基于内存chdb的真实ClickHouseClient实例
  })
})
setupTestClickHouse()
会自动注册vitest钩子:
  • beforeAll:创建chdb会话并从
    schema.sql
    加载架构
  • beforeEach:清空所有表以保证测试隔离
  • afterAll:销毁会话并清理临时文件
在新增ClickHouse迁移后,重新生成内存测试架构(仅当用户要求运行迁移相关命令时执行——参考database-clickhouse-weaviate):
bash
pnpm --filter @platform/db-clickhouse ch:schema:dump

Why not
vi.mock
?

为什么不使用
vi.mock

Mocking repositories with
vi.fn()
tests the wiring, not the queries. In-memory databases catch real bugs: wrong column names, broken
argMax
aggregations, incorrect
GROUP BY
clauses, and schema mismatches. They run quickly with zero external dependencies.
使用
vi.fn()
模拟仓库方法只能测试代码连接,无法测试查询逻辑。内存数据库可以捕获真实的bug:错误的列名、失效的
argMax
聚合、不正确的
GROUP BY
子句以及架构不匹配问题。它们运行速度快且无外部依赖。