测试数据与 Fixture

使用以下命令创建项目后:

goat init ./my-project \
  --name my-project \
  --git-repo git@github.com:your-user/my-project.git \
  --terminal-prefix MYAPP \
  --default-language en \
  --supported-languages en,pl \
  --template goatcms

你不仅会获得应用程序结构,还会获得与当前 Goat 版本匹配的示例数据和文档。

因此,你可以立即启动项目并查看包含示例内容的可运行应用程序,无需手动准备初始数据。

Fixture 因而具有两个作用:

  • 提供本地开发和测试所需的数据,
  • 创建与当前所使用生成器版本一致的示例文档。

这在更新项目时尤其有用。文档和示例可以与代码一同进行版本控制,因此更容易验证特定版本的应用程序如何运行。

项目的主 Fixture

负责加载数据的逻辑位于:

herd/fixture.goat

该脚本可以创建或更新以下内容:

  • 文档,
  • 示例数据,
  • 应用程序所需的记录,
  • 演示内容,
  • 本地开发期间所需的数据。

herd/fixture.goat 会在启动开发环境时通过以下方式执行:

herd/dev.goat

因此,启动项目后,本地应用程序可以自动获得运行所需的一组数据。

Fixture 也可以手动运行。

文档作为应用程序数据

示例文档存储在 Markdown 文件中。

默认结构如下:

herd/fixtures/doc/<ver>/<lang>/<slug>.md

其中:

  • <ver> 指定文档版本,
  • <lang> 指定语言,
  • <slug> 是文档的稳定标识符。

示例:

herd/fixtures/doc/v1/pl/architektura.md

这种方式允许将文档作为普通文本文件与项目一同存储。

你可以:

  • 在 Git 中进行版本控制,
  • 在代码审查中查看,
  • 在任意编辑器中编辑,
  • 借助 AI 修改,
  • 翻译,
  • 重新加载到应用程序中。

因此,文档仍是项目源代码的一部分,而不是仅存在于数据库中的内容。

加载 Markdown 文档

Markdown 文件通过以下方式加载:

herd/fixture.goat

并使用命令:

crud:doc:persist

示例:

crud:doc:persist \
  --lang=pl \
  --slug="moj-dokument" \
  --title="Mój dokument" \
  --description="Krótki opis dla wyszukiwarek i udostępnień." \
  --body-markdown-file="herd/fixtures/doc/v1/pl/moj-dokument.md"

文档内容直接从以下位置指定的文件中读取:

--body-markdown-file

标题、语言、slug 或描述等元数据会单独传递。

这样可以将实际的 Markdown 内容与供应用程序、SEO 或搜索机制使用的信息分离开来。

使用 persist 而非创建重复项

命令:

crud:doc:persist

设计为可重复运行。

它不会每次都创建新记录,而是根据标识符查找现有文档;如果文档已存在,则更新该文档。

因此,Fixture 可以是幂等的——多次运行同一脚本应产生相同的预期数据状态,而不是创建同一记录的更多副本。

对于继承自 content 的实体,文档标识基于以下组合:

lang + slug

例如:

pl + architektura
en + architecture

会被视为两个不同的文档。

因此,在更新现有内容时,请保持 lang 和 slug 的值一致。

更改 slug 可能会导致创建新记录,而不是更新原有记录。

稳定的 slug

应将 slug 视为文档的技术标识符,而不只是标题的简化版本。

好的 slug 应当:

  • 简短,
  • 稳定,
  • 使用小写字母,
  • 不含特殊字符,
  • 使用连字符分隔。

示例:

architektura
baza-danych
testowanie
model-i-generowanie

不要仅仅因为文档标题发生变化就修改 slug。

例如,文档:

slug: architektura

之后可以使用标题:

Architektura aplikacji Goat

而无需更改其标识符。

这有助于保持 URL 地址稳定,并通过 persist 正确更新记录。

文档版本管理

目录:

herd/fixtures/doc/<ver>/

可用于存储与特定项目或生成器版本关联的文档。

当 Goat 的后续版本改变以下内容时,这会很有用:

  • 项目结构,
  • 模型语法,
  • 可用命令,
  • 生成器行为,
  • 应用程序配置方式。

这样,用户便可以使用与其当前实际面对的代码版本相对应的文档。

这比仅依赖外部文档更安全,因为外部文档可能描述的是较新或较旧版本的工具。

手动运行 fixture

构建应用程序后,可以通过生成的应用程序 CLI 手动加载 fixture:

myapp run:script --path=herd/fixture.goat

以下情况会很有用:

  • 你修改了文档,
  • 你添加了新的示例数据,
  • 你想刷新应用程序的本地状态,
  • 你正在测试 fixture 的运行效果,
  • 你不想重新启动整个开发环境。

由于数据是通过 persist 类型的操作加载的,因此重新运行 fixture 时应主要更新现有记录,而不是创建重复记录。

日常工作中的 fixture

编辑文档时,典型的工作流程可能如下:

修改 Markdown 文件
        ↓
运行 herd/fixture.goat
        ↓
更新数据库中的文档
        ↓
在应用程序中检查结果

例如:

vim herd/fixtures/doc/v1/pl/architektura.md

myapp run:script --path=herd/fixture.goat

你无需手动将内容复制到数据库中,也无需通过管理面板编辑记录。

Fixture 与测试

Fixture 应创建可预测的初始状态。

好的测试数据应当:

  • 具有确定性,
  • 可以重复加载,
  • 独立于生产数据,
  • 不受手动操作顺序影响,
  • 足够完整,能够运行应用程序的基本场景。

在可能的情况下,如果测试之后会使用特定值,请避免生成随机数据。

稳定的数据有助于:

  • E2E 测试,
  • 调试,
  • 重现错误,
  • 为新开发人员准备环境,
  • 比较应用程序不同版本的行为。

示例数据与生产数据

Fixture 主要用于开发、测试和演示环境。

其中不要放入:

  • 真实用户数据,
  • 密码,
  • token,
  • API 密钥,
  • 密钥信息,
  • 包含机密信息的生产数据副本。

存储在 herd/fixtures/ 中的数据应被视为仓库的一部分,并假定任何拥有项目代码访问权限的人都可能访问这些数据。

文档编写指南

每个 Markdown 文件都应包含单一语言的内容。

通过目录结构和以下参数确定文档语言:

--lang

保持 slug 稳定,不要让其依赖标题的细微变化。

将标题和描述写入 fixture:

--title="Mój dokument"
--description="Krótki opis dokumentu."

这样,元数据会与数据定义一起存储,并可用于:

  • SEO,
  • 搜索,
  • 文档列表,
  • 内容分享,
  • 未来的语言版本。

而正文内容则存储在单独的 Markdown 文件中。

从首次启动即可使用的文档

由 goat init 提供的 fixture 的一项优势是,项目可以连同与其版本相对应的文档一起启动。

工作流简化如下:

goat init
    ↓
生成项目
    ↓
启动环境
    ↓
加载 fixture
    ↓
包含文档和示例数据的可用应用

因此,新项目不会从一个空应用开始。

从首次启动起,你就可以查看可运行的示例、数据结构,以及为所使用 Goat 版本准备的文档。

这使 fixture 不仅是加载测试数据的机制,也是自文档化项目的一部分。