如何为随时间推移发生的进程构建测试


How to structure tests for processes that occur over time?

构建没有

直接结果的代码测试的方法是什么?

假设我们有一个非常简单(但相当粗鲁)的过程:

  • 用户注册网站
  • 两天通票
    • 发送提醒电子邮件
    • 更新某些数据库字段
  • 十天通行证
    • 发送"c'ya"电子邮件
    • 删除帐户

我可以为每组子任务编写测试(发送电子邮件,更新数据库等)。但是,我如何编写结构良好的测试,其内容如下:

"注册两天后,应发送提醒电子邮件"注册十天后,帐户将被删除"

虽然我使用的是PHP和PHPUnit,但我觉得这个问题可能/可能不是语言不可知的。

基于事件机制的实现。例如,当代码中某处的事件侦听器收到带有用户 id 的事件user:reminder时,您只需要:

1) 通过手动发送该事件来测试提醒发送脚本:

$eventBus->init();
$eventBus->attachListener($reminderListener);
$eventBus->fire(new ReminderEvent($user->id));
$this->expect(...); // reminder must be `sent` 

2) 测试在时间流逝时生成事件:

$time = now();
$delay = ...;
$emitter = new RemindEventEmitter($user->id, $time + $delay)
$eventBus->addEmitter($emitter);
$eventBus->setCurrentTime($time); // when we just registered emitter...
$eventBus->run();
$this->expectNot(...); // ... that event _must not_ be fired
$eventBus->setCurrentTime($time + $delay); // manually skip $delay time ...
$eventBus->run();
$this->expect(...); // test that event _must_ be fired

并且事件生成/调度的事情(在我的示例中$eventBus)必须在可模拟/可替换的时间获取器上中继:

// in production code
$eventBus->setCurrentTime(now());
// elsewhere in tests
$eventBus->setCurrentTime(<point in time you want to test against>);