如何故意使 $model->save() 测试失败?

How to intentionally fail $model->save() for testing?

我的控制器中有这段代码class:

public function actionRevoke($id) {
    $model = Token::findById($id);
    $model->revoked_at = new Expression('NOW()');
    if ($model->save()) {
        Yii::$app->getSession()->setFlash('success', 'Revoked token');
    } else {
        Yii::$app->getSession()->setFlash('danger', 'Failed to revoke token');
    }
    return $this->render('revoke',['model' => $this]);
}

现在,运行带有代码覆盖率的CodeCeption,它告诉我,带有setFlash('danger',...)的部分没有被测试覆盖。

如何故意使 $model->save() 失败以触发 setFlash('danger,...) 指令?

我真的很喜欢它,如果我不需要向我的控制器添加额外的代码专门用于测试。所以特别是,如果可以避免的话,我不想要 if ($model->save() && !defined('TEST_FAIL_SAVE')) { 这样的东西。

解决方案是(如@scaisEdge 所建议的那样)使用验证规则。我添加了一条规则,它强制 $model->token 的长度恰好为 36。我的应用程序仅生成恰好 36 个字符长的标记。在我的测试中,我使用更新数据库中的行来将 abcd 显示为令牌,这显然少于 36 个字符。 由于此更改是在数据库级别进行的,因此它绕过了 Yii 的验证并提交到数据库。

在测试过程中,它更改了 $model->revoked_at 的值并尝试保存它,但由于 $model->token 太短而导致验证失败。

这里是测试函数中的相关部分,控制器的代码没有改动:

public function revokeToken(FunctionalTester $I){
    // login and navigation to relevant page
    Yii::$app->db->createCommand()->update('tokens',['token' => 'abcd'],['id' => 201 ])->execute();
    $I->click('a.btn.btn-danger');             /* click the 'revoke' button, this triggers actionRevoke($id) */
    $I->seeFlash('Failed to revoke token');    /* expect a flash message */
}