跳转到内容

测试与 CI

CI 由 GitHub Actions 运行,主要包含静态检查、类型检查、测试、构建、自动格式修复和文档部署。CircleCI 看门狗(.circleci/)镜像检查管线:当 GitHub Actions 对某个 commit 全部失败时(例如 GitHub 平台故障),CircleCI 会自动接管全量静态分析、多数据库测试矩阵与文档检查。构建、发布与部署仍仅由 GitHub Actions 负责。仓库本地自动化以 Taskfile.yml 为主入口。

终端窗口
task check
task test
task build
task ci

task check 覆盖 Ruff、Ruff format check、Markdown lint、Turbo lint、Pyright、ty 和 Turbo type check。task test 覆盖根 pytest、lingc-cli pytest 和 docs Vitest。task ci 会按顺序运行 check、test 和 build。

终端窗口
uv run -m ruff check . --output-format=github
uv run -m ruff format --check .
uv run -m pyright
uv run -m ty check --output-format github
uv run -m pytest

如果只改了某个模块,可以先跑相关测试文件,再按需要扩大范围。

修改钩子、适配器或启动流程后,仅静态检查不够。应执行下方三阶段真实启动冒烟测试,以捕获前向引用签名错误、导入顺序问题、schema 写入泄漏和 CLI 回归问题。

通过 ENVIRONMENT=dev 选择开发环境,让 NoneBot2 载入 .env + .env.dev 并启动机器人:

终端窗口
uvx --from nb-cli nb.exe run

需观察到 Application startup complete. 并至少完成一个事件周期。如需限制运行时间,可用 timeout 包裹命令(例如 timeout 10s);超时杀死进程时返回退出码 124,属于预期行为。若进程在启动完成前退出,请增加超时时间。

阶段 2 — 生产环境(清理 localstore)

Section titled “阶段 2 — 生产环境(清理 localstore)”

验证机器人能从干净的 localstore 状态启动,证明启动过程不写 schema 且能在全新部署下存活。

  1. 删除项目下所有 localstore 管理的目录:

    终端窗口
    rm -rf config/nonebot_plugin_lingchu_bot/ \
    data/nonebot_plugin_lingchu_bot/ \
    data/nonebot_plugin_orm/ \
    cache/nonebot_plugin_lingchu_bot/

    这四个路径由 nonebot_plugin_localstore 解析(在 .env 中设置 LOCALSTORE_USE_CWD=true)。仓库根目录的 config/、data/、cache/ 是本地开发产物,可丢弃。

  2. 设置 ENVIRONMENT=prod 让 NoneBot2 载入 .env + .env.prod 并启动机器人:

    终端窗口
    ENVIRONMENT=prod uvx --from nb-cli nb.exe run
  3. 验收标准:进程到达 Application startup complete. 且无硬错误。LLM configuration missing or invalid; AI is unavailable 告警可接受;任何 traceback、schema 写入或迁移副作用都是硬错误。

除手动的运行时冒烟测试外,CI/CD 在 build job 之后、部署之前运行自动化的冒烟测试阶段,验证构建产物镜像能够启动 NoneBot、注册运行时钩子、初始化核心服务并生成 JUnit 报告。

  • smoke-test 在 👷 CI-builds 的 build job 之后运行,仅在构建成功时触发。
  • docs-smoke 在 📚 Docs Deploy 的 docs build 之后运行,仅在文档构建成功时触发。

任意冒烟检查失败时,工作流会立即终止,不会进入部署环节。job 会上传产物 smoke-test-results.xml,方便查看失败断言与 traceback。

可以使用以下命令在本地执行同样的冒烟检查:

终端窗口
# 使用 Docker Compose 构建并运行冒烟测试容器
task smoke
# 以 CI 模式运行并输出 JUnit XML 报告
task ci:smoke
# 等效的原始 Docker Compose 命令
docker compose --profile smoke up --build --abort-on-container-exit smoke-test

项目通过 SQLALCHEMY_DATABASE_URL 环境变量支持 4 个数据库后端测试,遵循 NoneBot 数据库测试最佳实践。

默认使用 SQLite 进行测试。要在 PostgreSQL / MySQL / MariaDB 上本地测试:

  1. 安装数据库驱动(已在 test 依赖组中):
终端窗口
uv sync --all-groups
  1. 启动数据库服务器(通过 Docker 或本地安装)。

  2. 设置 SQLALCHEMY_DATABASE_URL 环境变量并运行测试:

终端窗口
# PostgreSQL
export SQLALCHEMY_DATABASE_URL="postgresql+psycopg://postgres:postgres@localhost:5432/postgres"
uv run -m pytest
# MySQL
export SQLALCHEMY_DATABASE_URL="mysql+aiomysql://mysql:mysql@localhost:3306/mymysql"
uv run -m pytest
# MariaDB(使用 mysql+aiomysql,SQLAlchemy 通过 VERSION() 自动检测 MariaDB)
export SQLALCHEMY_DATABASE_URL="mysql+aiomysql://mariadb:mariadb@localhost:3306/mymariadb"
uv run -m pytest
  1. 测试前运行迁移:
终端窗口
uv run nb orm upgrade

CI 跨 4 个数据库引擎跑 8 个任务,覆盖 LTS 与最新版:

  • SQLite(默认,无需额外服务;版本由 Python sqlite3/aiosqlite 决定)
  • PostgreSQL 16(postgres:16-alpine,支持至 2028-11)与 PostgreSQL 18(postgres:18-alpine,最新版)
  • MySQL 8.4 LTS(mysql:8.4,支持至约 2032)与 MySQL 9.7 LTS(mysql:9.7,支持至约 2034)
  • MariaDB 11.4 LTS(mariadb:11.4,支持至 2029-05)与 MariaDB 11.8 LTS(mariadb:11.8,支持至 2028-06)

每个矩阵条目携带 engine + image 字段;服务容器通过 ${{ matrix.db.engine == '<engine>' && matrix.db.image || '' }} 选择镜像,使同一引擎的多个版本可在一个矩阵中共存。fail-fast: false 策略确保即使一个数据库失败,所有数据库仍会被测试。

文档站使用 pnpm、Astro Starlight、Vitest、Playwright、ESLint 和 Turbo:

终端窗口
pnpm --filter docs lint
pnpm --filter docs test
pnpm --filter docs run test:e2e:hook
pnpm --filter docs run test:e2e
pnpm --filter docs check-types
pnpm turbo run build --filter=docs

Vitest 覆盖 apps/docs/src/__tests__ 下的组件和库行为。Playwright 测试放在 apps/docs/e2e,覆盖浏览器级文档导航。本地 hook 在 docs 变更时运行 Chromium 冒烟命令(test:e2e:hook);CI 运行全部配置的 Playwright 浏览器项目,并上传 HTML report 与 trace 产物。

编写 Playwright 测试时优先使用 role/text locator 和 toBeVisible()、toHaveAttribute() 等 web-first assertion。除非变更明确需要,否则不要使用 sleep、截图断言或宽泛的视觉检查。

终端窗口
pnpm exec markdownlint-cli2

glob 与 ignore 列表由仓库根目录的 .markdownlint-cli2.jsonc 统一配置,无需传入路径参数。

修改可翻译字符串后运行:

终端窗口
task i18n

如果只修改文档中的 i18n 说明,不需要重新生成 gettext catalog。

  • 🧪 Python CI:共享的 detect-changes 复合 action(.github/actions/detect-changes)按文件类型输出布尔标志(python/markdown/frontend/frontend-code/frontend-style/frontend-content/frontend-tsx),然后条件触发 Static Analysis(Python 或 markdown 变更时,通过 task ci:static)和 Tests & Type Check(Python 变更时,跨多数据库矩阵)。Auto Fix & Format 在 main/dev push 时运行。条件与 pre-commit v3 的 NEEDS_LINT/NEEDS_TYPE_CHECK/NEEDS_DOCS_TEST 对齐。
  • 🧪 Frontend CI:使用同一个 detect-changes action,然后条件触发 Docs Check — ESLint 在代码/样式变更时,check-types 在任意前端变更时,link validation 在内容变更时,Vitest 在代码/内容变更时。
  • 🎭 Playwright:针对 apps/docs 和 packages 变更运行 docs E2E 测试,安装浏览器依赖,并上传 Playwright report 产物。
  • 👷 CI-builds:运行 task ci:build;versioned-build 作业改为每日定时(北京时间 02:00,UTC 0 18 * * *)——从最新 tag 同步版本、bump dev version、写回 core_version、构建、归档产物、生成 provenance 并提交 tag。
  • 📚 Docs Deploy:docs 相关路径 push 到 main 或 dev 时,运行 pnpm/turbo lint、docs test 和 docs build,然后部署 GitHub Pages。

打开失败 job 日志,定位命令、规则和行号。修复时只改导致失败的最小范围,并重新运行对应本地命令。