# 关于 ActivityPub 单元测试的一些思考
来源:https://shkspr.mobi/blog/2026/10/some-thoughts-on-unit-testing-activitypub/
我要在这里彻底坦诚一把——我从来就没真正理解"测试驱动开发"这个理念。我更倾向于"直接 telnet 到生产环境,管他什么后果"那种人。你看,那样好玩多了,而且我的心脏病医生也建议时不时来点剧烈刺激。
单元测试的本质其实很简单:
1. 给函数喂一些数据
2. 看它怎么响应
喂它好数据,如果它返回 `true`,测试就通过。喂它坏数据,确保它返回 false。小菜一碟。
作为我 NLnet 资助的 ActivityBot 项目(https://shkspr.mobi/blog/2026/08/activitybot-is-the-recipient-of-an-nlnet-grant/)的一部分,我正在为我的机器人框架编写一些正式的测试。我希望其中一些能对做类似事情的其他项目有所帮助。
测试主要有四大类——下面是我编写这些测试时发现的问题。
## 基本文本验证(https://shkspr.mobi/blog/2026/10/some-thoughts-on-unit-testing-activitypub/#basic-text-validation)
一个基本的测试可能是如何验证一个 ActivityPub 用户名是否有效。通常是类似 `@
[email protected]` 这样的格式——我们对此做了哪些假设?它以 `@` 开头,中间还有另一个 `@`,将其分为两部分:用户和服务器。服务器必须是一个有效的域名——但这可以包括非 ASCII 的国际化域名(Internationalised Domain Names)和 Emoji 域名。
那用户部分呢?它只是 A-Z 和 0-9 吗?能包含点号吗?能像电子邮件地址一样包含撇号吗?
基本上,要找到 ActivityPub 各个组件部分的规范有多容易?一点都不容易!
## 消息验证(https://shkspr.mobi/blog/2026/10/some-thoughts-on-unit-testing-activitypub/#message-validation)
一个 WebFinger 响应(https://www.rfc-editor.org/info/rfc7033/)是什么样子的?哪些部分是必须的?它们可以包含什么值?
对于你的项目生成的任何消息,你怎么能确定其他 ActivityPub 服务器能理解它?
同样,当我们从外部服务器收到一个关注(follow)消息时,它应该是什么样子的?
有一些 JSON Schema(https://github.com/steve-bate/fediverse-jsonschema)可以用来验证某些类型的消息。
但是,同样的问题又来了——有*大量*分散在各处的规范。
## 签名验证(https://shkspr.mobi/blog/2026/10/some-thoughts-on-unit-testing-activitypub/#signature-verification)
正如我之前写过的,HTTP Signatures 很难搞(https://shkspr.mobi/blog/2026/09/a-reasonably-practical-guide-to-validating-rfc-9421-http-signatures-for-activitypub-in-php/)。有两个主要问题。第一个是验证签名。
为了做到这一点,你需要收集一堆签名,然后找到一种方法将它们回放到测试中。所以我正在保存签名,以便之后可以与其他人分享。
第二个问题是*生成*签名。当然,你可以对签名运行测试——但只有一种*真正*的方法来测试它们是否被接受……
## 与他人通信(https://shkspr.mobi/blog/2026/10/some-thoughts-on-unit-testing-activitypub/#communicating-with-others)
如果你不能与他人通信,他们也不能与你通信,那么测试通过就毫无意义。
有些测试比其他测试更容易。发送签名请求应该是简单且可重复的。但接收消息不容易自动化。它需要能够控制一个外部服务器,并要求该服务器发送消息。
使用 Mastodon API(https://docs.joinmastodon.org/client/intro/)可以发出与你的服务器交互的请求——但前提是它是一个*公开*的服务器。
## 综合起来(https://shkspr.mobi/blog/2026/10/some-thoughts-on-unit-testing-activitypub/#putting-it-all-together)
我把我所有的测试都放在了网上(https://gitlab.com/edent/activity-bot/-/tree/main/tests?ref_type=heads)。我还在分享一个[消息和签名的集合](https://gitlab.com/edent/activity-bot/-/tree/main/tests/headers?ref_type=heads),你可以在你的测试中使用。
我很想知道你是否觉得它们有用。