Temporal Workflow 测试用例编写指南
Temporal Workflow 测试用例编写指南
引言
篇指南旨在为初次使用 Temporal 的开发者提供一个清晰、易懂的 Workflow 测试用例编写框架。Temporal 作为一个强大的工作流编排引擎,其测试框架也同样功能丰富。
为了循序渐进,本次我们先将重点放在 Workflow 的测试用例编写上,关于 Activity 的测试用例,我们将在下一篇文章中详细探讨。
Workflow 测试的两大核心
要成功运行一个 Workflow 测试用例,重点依赖于两个关键部分:测试环境初始化 和 Mock Activity。
1. 测试环境初始化
Temporal 提供了一个专用的测试框架,允许你在内存中执行 Workflow,而无需依赖真实的 Temporal 服务。这大大加快了测试速度并简化了环境配置。
一个典型的初始化过程如下:
1 | // 引入测试包 |
通过 testsuite.NewTestWorkflowEnvironment(),我们就创建了一个隔离的测试环境 env,后续所有的测试操作都将围绕它进行。
2. Mock Activity
在单元测试中,我们希望专注于测试 Workflow 本身的逻辑,而不是它所调用的 Activity。因此,我们需要对 Activity 进行 Mock(模拟)。
Mock Activity 的好处是:
- 隔离性:避免外部依赖(如数据库、API 调用)对测试造成干扰。
- 速度快:直接返回预设结果,无需执行真实的、可能耗时的 Activity 逻辑。
- 可预测性:可以精确控制 Activity 的返回值和错误,从而测试 Workflow 在不同情况下的行为。
Mock 的基本操作如下:
1 | func (s *MyWorkflowTestSuite) TestMyWorkflow_Success() { |
s.env.OnActivity(...) 这行代码就定义了当 MyActivity 被调用时应该发生的行为。
一些实用的测试方法
Temporal 的测试框架提供了一些非常实用的工具函数,可以帮助我们处理各种复杂的测试场景。
SetOnTimerFiredListener(listener func(timerID string))
这个函数用于监听定时器(Timer)触发事件。在测试环境中,为了加速测试执行,Workflow 中的休眠(如workflow.Sleep)或定时器会被自动跳过。如果你需要模拟真实的等待时间或在定时器触发时执行特定逻辑,这个函数就非常有用。因为测试用例中,workflow的休眠会被跳过,所以需要使用SetOnTimerFiredListener来模拟休眠。例如,你可以用它来在测试中引入真实的延时:
1
2
3
4s.workflowEnv.SetOnTimerFiredListener(func(timerID string) { // 真正的休眠避免快速跳过
s.T().Logf("timerID: %s will sleep 2 seconds", timerID)
time.Sleep(time.Second * 2)
})当你的 Workflow 中有
workflow.NewTimer或workflow.Sleep逻辑时,你可以通过这个监听器来执行回调,从而模拟更真实的场景或进行相关的断言。SetWorkflowRunTimeout(timeout time.Duration)
设置 Workflow 的最大运行时间。如果 Workflow 执行时间超过这个阈值,测试将失败。这对于防止测试用例因逻辑错误而无限期阻塞非常有用。RegisterDelayedCallback(callback func(), delay time.Duration)
注册一个延迟回调。这个函数非常适合用来测试需要与 Workflow 进行异步交互的场景。例如,你可以在 Workflow 启动后的某个时间点,通过这个回调来发送一个 Signal。SignalWorkflow(name string, value interface{})
向正在运行的 Workflow 发送一个信号(Signal)。这是测试 Workflow 对外部信号响应的核心方法。你可以用它来模拟用户操作、外部事件等。1
2
3
4
5// ... 在 ExecuteWorkflow 之后
// 注册一个回调,在 1 秒后向 Workflow 发送信号
s.env.RegisterDelayedCallback(func() {
s.env.SignalWorkflow("my-signal", "signal-data")
}, time.Second)
常见问题排查
StartToCloseTimeout
当你在运行测试用例时,如果遇到 StartToCloseTimeout 错误,这通常意味着测试用例被阻塞了,Workflow 未能在预期的时间内完成。
最常见的原因之一,是 Workflow 自身的逻辑进入了无法继续执行的状态。一个典型的例子就是等待一个永远不会有新消息的 Channel。
考虑以下 Workflow 代码片段:
1 | func MyWorkflow(ctx workflow.Context, data string) error { |
如果在你的测试用例中,启动了这个 Workflow 却忘记了使用 s.env.SignalWorkflow("my-signal", ...) 来发送信号,那么 Workflow 将会永远阻塞在 signalCh.Receive 这一行,最终导致 StartToCloseTimeout 错误。
排查思路:
- 仔细检查 Workflow 代码中所有可能引起等待或阻塞的地方,例如
selector.Select,channel.Receive,workflow.Sleep(如果时间过长)等。 - 确保你的测试用例覆盖了所有必要的交互,比如发送相应的信号(Signal)或执行回调。
官方资源:Temporal AI 助手
最后,分享一个实用的资源。Temporal 的官方文档网站内嵌了一个 AI 助手。如果你在开发或测试中遇到难以解决的问题,不妨试试向它提问,它有时能提供意想不到的帮助和解决思路。

希望这篇指南能帮助你顺利开启 Temporal 的测试之旅!









