首页 > 解决方案 > Laravel - 在单元测试中伪造保存失败

问题描述

如果我们想要测试以下代码,那么模拟失败保存的最佳方法是什么?目前,我的测试中唯一缺少的部分是else声明。

保存是循环的一部分,我们$customers循环遍历它们并执行一些操作。

$customers = Customer::where('created_at', '<=', $start);

$customers->each(function ($customer, $key) {
    if ($customer->save()) {
        //Do something here
    } else {
        //Saving failed, log something
    }
}

测试的所有数据都来自工厂,并在每次测试时动态生成。

标签: laravelphpunit

解决方案


好吧,简单但肮脏的事情是通过saving事件假装保存失败:

这是事件处理程序的注释:

public function save(array $options = [])
{
    $query = $this->newModelQuery();

    // If the "saving" event returns false we'll bail out of the save and return
    // false, indicating that the save failed. This provides a chance for any
    // listeners to cancel save operations if validations fail or whatever.
    if ($this->fireModelEvent('saving') === false) {
        return false;
    }
   ....

因此,类似以下的东西应该起作用:

class TestModelSaving {
     public function testSaveFailureLogs() {
          // Create the fake model here
          // If the event handler for saving returns false then `save()` will return false
          Customer::saving(function () { return false; }); 
          // Call your unit under test here

          // Cleanup: Usually unnecessary, but some test configurations might need it
          Customer::flushEventListeners();

     }
}

为了测试是否记录了事情,您可以通过模拟记录器外观Log::shouldReceive(....)(参数与具有相同名称的模拟函数相同)


推荐阅读