← 返回首页目录
# 构建可靠的 Backstage 百科查询与测试体系
**作者:吉祥法师**
在软件工程和云原生生态系统中,Backstage 作为一个开发者门户平台,其核心价值在于充当一个组织内部的“百科全书”。用户常提及的“Test+query for encyclopedia backstage”,本质上是指一种能力:能够自信且可重复地检索到正确的 Backstage 记录和 TechDocs 页面,并通过可复现的测试来验证这一过程。本文将提供一份实战手册,详细阐述如何利用 Backstage 的 GraphQL API 查询目录实体、利用 TechDocs 获取百科内容,以及利用搜索后端验证“当我搜索时,结果确实出现”的可靠性。
## 核心概念
要理解并构建一个可测试的 Backstage 百科查询体系,必须首先明确其构成要素:
1. **目录实体(Catalog Entities)**:这是百科的基础骨架,定义了系统中存在什么,包括系统(Systems)、组件(Components)、API、所有者(Owners)等。它们是信息的锚点。
2. **TechDocs 页面**:这是百科的血肉,提供了与目录实体相关联的详细文档内容。它们是用户最终阅读和获取知识的载体。
3. **搜索索引(Search Index)**:这是百科的导航,允许用户通过文本和元数据快速找到相关文档。它是提升用户体验的关键。
因此,高效的“测试+查询”意味着验证两个层面的正确性:一是检索的正确性(能否找到实体和文档),二是面向用户的结果的正确性(搜索结果是否匹配预期,页面能否正常渲染)。
## 逻辑结构与主要论点
本文的逻辑结构遵循从理论基础到实战演练、从单一组件测试到端到端验证的递进路径。核心论点是:一个可靠的查询与测试体系应建立在**分层测试**的策略之上,通过单元测试、集成测试和端到端测试,层层递进地验证不同环节的正确性,从而快速定位并解决回归问题。文章将逐一剖析查询目录、渲染文档、验证搜索和模拟用户旅程这四大关键环节。
## 准备工作与数据流理解
在编写任何测试或执行查询前,必须锁定开发环境的基础版本,因为 Backstage 迭代迅速,GraphQL 模式和插件 API 可能发生变化。
- **Node.js**:使用 18.x 或 20.x LTS 版本。
- **Yarn**:根据你 Backstage 发行版使用 1.x 或 3.x。
- **Backstage**:明确你仓库中 `packages/app/package.json` 所指定的版本。
- **TechDocs**:确保已启用并配置好(本地或云端发布)。
- **搜索后端**:配置好你选择的搜索后端(本地开发常用 Elasticsearch/OpenSearch,生产环境通常使用托管搜索)。
在无法正常运行的 Backstage 实例上,一切都是空谈。请先确保基础的 Backstage 应用已成功搭建,并在界面上看到目录和 TechDocs 的正常渲染。
理解 Backstage 的数据流是编写高效查询测试的基础。典型的流程如下:
1. **目录导入(Catalog Ingest)**:`catalog-info.yaml` 文件定义了实体及其与 TechDocs 的关联关系。
2. **TechDocs 生成/发布(TechDocs Generation/Publishing)**:文档被构建并存储,以便 Backstage 可以渲染它们。
3. **UI 请求(UI Requests)**:前端(Frontend)通过目录 GraphQL API 或 TechDocs 端点请求数据。
4. **搜索索引(Search Indexing)**:文档和实体元数据被索引,确保搜索结果的准确性。
你的测试策略应模拟这些步骤:单元测试验证函数逻辑,集成测试验证 API 行为,端到端测试验证最终用户体验。
## 实战方法一:通过 GraphQL 查询目录实体
大多数 TechDocs 设置都将文档关联到目录实体。因此,查询链的第一个检查点是目录。
**调用目录 GraphQL API**
Backstage 的目录 GraphQL 通常提供 `entity` 和 `entities` 查询。虽然具体模式可能因版本而异,但其基本模式是稳定的:为给定的 `kind`、`namespace` 和 `name` 执行查询。
典型的 GraphQL 查询结构如下:
```graphql
query EntityByName($kind: String!, $namespace: String!, $name: String!) {
entity(kind: $kind, namespace: $namespace, name: $name) {
apiVersion
kind
metadata {
name
namespace
title
}
}
}
```
在前端代码中,你通常使用 Backstage 的 GraphQL 客户端。在后端代码中,你可以直接在集成测试中调用此 GraphQL 模式。
**集成测试模式:验证实体查找**
编写一个集成测试,它会执行以下步骤:
1. **数据准备(Seeding)**:在测试环境中植入一个测试用的目录实体。这通常可以借助 `@backstage/catalog-client` 或直接向目录后端 API 发送创建请求来完成。
2. **执行查询**:调用目录 GraphQL 端点,传入测试实体的 `kind`、`namespace` 和 `name`。
3. **结果断言**:断言返回的字段(如 `kind`、`name`、`title`)与预期一致。
即使后续的 TechDocs 渲染失败,这个测试也能首先告诉你,目录映射是否存在问题。
**常见错误点**
- **命名空间错误(Wrong Namespace)**:许多团队忘记默认命名空间并非总是 `default`。在测试时,务必明确你使用的命名空间。
- **实体类型不匹配(Kind Mismatch)**:当文档关联到 `system` 类型,但你却用 `component` 类型查询时,TechDocs 的解析可能会失败。
- **标题缺失(Title Assumption)**:并非所有实体都定义了 `metadata.title` 字段。在测试断言中,应优先使用 `name` 等必选字段。
## 实战方法二:查询 TechDocs 内容
一旦确认实体存在,下一步是验证百科页面能否正常渲染。
**选择正确的 TechDocs 端点行为**
TechDocs 可以配置为本地生成或云端发布。对于测试,重点应放在一个稳定的契约上:给定一个实体引用,文档查看器能够检索到渲染后的内容,并且页面路由存在,其中包含预期的 HTML 标记或已知的标题。
**后端集成测试:渲染一个已知页面**
使用一个确定性的文档固定文件(fixture),这是最可靠的方法。
1. **创建固定文件(Fixture)**:在你的测试实体目录下创建一个 `docs` 文件夹(例如 `docs/index.md`),并在其中添加一个独特且稳定的标题,如 `# Runbook Checklist`。
2. **确保生成环境可用**:在你的测试环境中,必须确保 TechDocs 的生成和发布流程是可用的。如果使用本地生成,可以直接触发;如果使用云端发布,可能需要模拟或绕过延迟。
3. **调用渲染路由**:调用文档查看器所使用的后端路由。
4. **断言内容**:断言响应内容包含了 `Runbook Checklist` 这个已知标题。
这个测试可以精准地捕捉到由链接损坏、生成失败或配置漂移引起的问题。
**棘手的边界情况**
- **文档发布延迟(Stale Published Docs)**:云端发布可能存在延迟。测试应该等待发布完成,或者为了方便和稳定,在测试环境中使用本地生成路径。
- **实体引用不匹配(Entity Reference Mismatch)**:TechDocs 的解析通常依赖于实体的 `kind`、`name`、`namespace` 以及特定的注解。任何一环的错误都会导致渲染失败。
- **Markdown 构建差异(Markdown Build Differences)**:不同的 Markdown 处理插件或主题配置可能导致内容构建失败。
## 实战方法三:测试搜索索引
即便 TechDocs 可以渲染,用户更关心的是搜索能否返回正确的结果。这是搜索索引测试的价值所在。
**测试百科搜索的内容**
对于一个诸如“incident response checklist”的查询,你需要确认三点:
1. 文档页面已被成功索引。
2. 搜索结果的摘要/预览与匹配的章节相对应。
3. 权限配置没有意外地隐藏了搜索结果。
**集成测试方法:先索引后查询**
由于搜索索引通常是异步的,这类测试会耗费更多时间。
1. **植入文档**:为一个实体植入一个包含独特短语的 TechDocs 页面,例如 `SLA triage steps`。
2. **触发索引**:根据你的配置,自动或手动触发索引任务。
3. **等待并查询**:添加一个带有超时限制的轮询循环(例如,最长等待 60 秒),让测试不至于因为索引延迟而立即失败。之后,使用查询 API 搜索该短语。
4. **断言结果**:断言搜索结果包含预期的文档标题或 URL。
**具体隐患:搜索分析器不匹配**
不同的搜索后端(如 Elasticsearch)会使用词干提取器(stemming)和分析器(analyzer)来处理文本。如果你在单元测试中做了一个精确短语匹配,但搜索后端却使用了分词(tokenization),那么集成测试的结果可能与你预期的不符。因此,集成测试应基于搜索实际返回的内容(如标题、URL)进行断言,而不是仅仅匹配原始字符串。
## 实战方法四:使用 Playwright 进行端到端测试
端到端测试是将“本地可运行”转化为“用户可使用”的最后一道关卡。你不需要几十个流程,但需要几个能证明百科流水线正常工作的关键流程。
**Playwright 场景:捕捉真实回归**
1. **打开应用**:启动 Backstage 应用。
2. **执行搜索**:在搜索框中输入一个存在于你的 TechDocs 固定文件中的关键词。
3. **点击结果**:点击搜索到的结果。
4. **断言渲染**:断言渲染后的页面包含已知的标题(如 `# Runbook Checklist`)。
因为 Playwright 运行在真实的浏览器环境中,它能够捕获后端测试无法发现的路由问题、资源缺失问题以及权限问题。
**如何稳定地断言(Keep It Stable)**
- 优先断言 Markdown 文档中的**稳定标题**或独特文本。
- 避免断言根据主题版本而变化的动态 DOM 结构。
- 可以同时断言最终页面的 URL 路径和页面内的一个独特内容标记。
## 常见故障模式与解决方案
理解并掌握下面这些常见的故障模式,可以帮助你在遭遇“百科查询失败”时快速定位问题。
1. **目录查询成功,但 TechDocs 返回 404**
- **检查点**:确认该实体是否拥有 TechDocs 注解(通常是 `backstage.io/techdocs-ref`)。确认 TechDocs 的生成/发布是否已为该实体完成。如果使用云端发布,确认发布管道没有延迟。
2. **TechDocs 渲染成功,但搜索无结果**
- **检查点**:确认搜索索引服务已配置并正常运行(检查搜索后端的凭证和索引名称)。确认文档内容没有被索引排除规则过滤掉。验证搜索查询的分析器是否与预期匹配。
3. **搜索返回结果,但用户无法打开**
- **检查点**:权限不匹配--测试用户的权限可能不足以访问该实体。目录实体映射缺失--索引的文档引用无法找到对应的目录实体。搜索结果构建器中的 URL 生成错误。
4. **异步任务导致测试不稳定(Flaky Tests)**
- **解决方案**:在涉及索引的断言中使用带有明确超时的**轮询机制**。在 CI 环境中,隔离测试任务,确保索引作业不会与其他测试运行冲突。如果可能,在每次运行之间清除搜索索引。
## 安全与权限注意事项
Backstage 的权限系统可以改变你的查询结果。这有助于安全,但对测试来说是麻烦的,除非你主动处理它。
**在显式认证上下文中测试**
集成测试应包括一个确定性的身份和角色设置。如果你的文档是受到权限控制的,你需要测试两种情况:
- **授权用户**:可以查询实体并打开 TechDocs 页面。
- **未授权用户**:无法看到页面(搜索也不应暴露 URL)。
**不要混淆“无结果”与“索引错误”**
如果搜索返回零结果,在断定索引系统损坏之前,请先确认你是否因为权限问题被阻止了。
## 总结与最佳实践
一个可靠的“Test+query for encyclopedia backstage”工作流,始于目录 GraphQL 的正确性验证,继而通过固定的文档固定文件证明 TechDocs 能正常渲染,最后通过搜索索引验证来模拟真实的用户行为。
将你的测试结构化地分为三个层次:**单元测试**(测试查询构建器和解析逻辑)、**集成测试**(使用测试数据库和搜索桩运行,针对实际的后端处理器)和**端到端测试**(Playwright 检查 UI 渲染和搜索结果)。一旦你遵循这种分层结构,回归问题就不再神秘,而是变成可诊断、可追溯的。
**最佳实践清单**:
- **分层测试**:遵循单元 → 集成 → E2E 的顺序。
- **使用固定文件(Fixtures)**:为 TechDocs 页面创建确定性的、包含唯一标题的 Markdown 文件。
- **异步操作使用轮询**:对搜索索引等异步操作使用带有超时的轮询机制。
- **测试授权与未授权场景**:确保你的测试覆盖了不同的用户上下文。
- **优先断言稳定元素**:在 E2E 测试中,优先断言页面标题,而非易变的 DOM 结构。