如何测试处理 Eloquent 模型的 Laravel 包?

ala*_*iva 5 php unit-testing mocking laravel eloquent

我创建了一个操作 eloquent 模型的包,并为它创建了测试用例。

该包应该调用save()delete()模型,在某些时候会尝试访问数据库。

实际数据库方法

作为第一次尝试,我尝试了这种方法以及这种. 关键是在包的上下文中(甚至使用orchestra/testbench),我需要配置数据库和迁移。由于包本身没有任何模型(但我为测试目的创建了一个虚拟模型)我认为这种方法可能有点矫枉过正。无论如何,我仍然接受在内存中设置一个准备好的sqlite db,我也尝试过但无法使其工作(它试图使用forge连接sqlite,但我无法使其访问另一个连接。我可以提供详细信息关于我为它所做的)。

模拟方法

另一种可能的尝试(根据我对此的有限理解)是部分模拟模型。但是在我嘲笑它之后,它不知道如何处理其他调用,例如fill()我愿意的常见行为,但是我收到了一个方法未找到异常。

方法覆盖方法

鉴于这两种可能的尝试都失败了,我默认采用对我有用的第三种可能的方法,但老实说,我不确定这是否是解决方法。

为了避免在调用save()delete()方法时由于缺少数据库而导致测试失败,我覆盖了它们(完整源代码在这里):

class DummyContact extends Model
{
    // ...

    public function save(array $options = [])
    {
        $this->exists = true;
        $this->wasRecentlyCreated = true;
    }

    public function delete()
    {
        $this->exists = false;
        $this->wasRecentlyCreated = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,我就可以测试以下代码(此处完整源代码):

public function unifyOnBase()
{
    $mergeModel = $this->merge();

    $this->modelA->fill($mergeModel->toArray());
    $this->modelA->save();
    $this->modelB->delete();

    return $this->modelA;
}
Run Code Online (Sandbox Code Playgroud)

所以我的问题是,这种方法可以接受吗?(我认为这是公平的,我没有看到特殊的陷阱,但我怀疑存在更优雅的方法)。如果有建议的方法,比如 Mocking 或使用实际的 DB 来运行测试,我想知道我应该对我的测试代码库进行哪些调整以进行测试

最后但重要的说明:我不愿意测试模型本身,我愿意测试我使用的代码(因此取决于模型)。

ala*_*iva 3

感谢 Jonas Staudenmeir 的评论:

与实际数据库的集成测试是测试代码的最彻底的方法。IMO,您至少应该对基本功能进行集成测试。这就是我如何使用 SQLite 数据库来测试我的包。

我可以配对并开始使用内存中的 sqlite方法。

  1. 删除了覆盖功能

  2. 按照此工作项目添加了 Capsule 测试用例设置代码作为示例(谢谢

  3. 就我而言,我还需要安装 sqlite 驱动程序sudo apt-get install php7.2-sqlite

现在测试仍然可以成功运行,而解决方案看起来更优雅,并清理了函数覆盖变通办法,这些变通办法很容易在 Eloquent 模型的 API 升级时被破坏。这还可以更轻松地访问测试包的依赖于关系的功能。

测试通过