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

6
我创建了一个操作 eloquent 模型的包,并为其创建了测试案例。 这个包在某些时候会调用模型的 save()delete() 方法,从而尝试访问数据库。
实际数据库方法 首先我尝试了这种方法这种方法。问题在于,在包的上下文中(即使使用orchestra/testbench),我需要配置数据库和迁移。由于包本身没有任何模型(但我已经为测试目的创建了虚拟模型),所以我认为这种方法可能有点过度。无论如何,我仍然可以接受在内存中设置准备好的 sqlite 数据库,我也尝试过,但无法使其正常工作(它正在尝试使用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;
    }
}

这样,我就能够测试以下代码(完整源代码在此:链接):
public function unifyOnBase()
{
    $mergeModel = $this->merge();

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

    return $this->modelA;
}

所以我的问题是,这种方法可行吗?(我认为它是公平的,我没有看到异常的缺陷,但我怀疑存在更优雅的方法)。如果有建议的方法,比如模拟或使用实际的数据库运行测试,我想知道我应该对我的测试代码库进行哪些调整
最后但很重要的一点:我不想测试模型本身,我想测试使用模型的我的代码(因此依赖于模型)。

1
使用实际数据库进行集成测试是测试代码最彻底的方法。在我看来,您至少应该为基本功能编写集成测试。在这里是我如何在我的软件包测试中使用SQLite数据库。 - Jonas Staudenmeir
这正是我想让它工作的方式。我会尝试配合你的方法并发布结果。感谢参考。 - alariva
2个回答

3

感谢Jonas Staudenmeir的评论:

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

我可以配对并使内存中SQLite方法运行。

  1. 移除覆盖函数

  2. 添加胶囊测试用例setUp代码,参考这个工作项目作为例子感谢那位

  3. 在我的情况下,我还需要安装sqlite驱动程序sudo apt-get install php7.2-sqlite

测试现在仍然成功运行, 而解决方案看起来更加优雅,清理了函数覆盖的解决方法,这些解决方法在Eloquent模型的API升级时很容易被破坏。这也将使得更容易访问包中依赖关系的测试功能。

Test pass


2
我认为你的第一个提议,即“实际数据库方法”是最好的 - 使用orchestra/testbench包。
由于你的包中没有Eloquent模型,但是你的包修改了Eloquent模型,所以我认为你应该在测试文件夹内只为测试目的创建一个Eloquent模型。
例如,将DummyContact放入tests/Models/DummyContact.php中,并将迁移文件放入tests/Database/Migration/DummyContactMigration.php中。
现在,你需要做的就是设置一个基本的TestCase.php。确保显式调用你的DummyContact模型的迁移文件。
下面是一个例子:
<?php

namespace MyVendor\MyPackage\Tests;

use MyVendor\MyPackage\MyServiceProvider;

class TestCase extends \Orchestra\Testbench\TestCase
{
    public function setUp(): void
    {
        parent::setUp();

        $this->loadMigrationsFrom(__DIR__ . '/database/migrations');
        $this->artisan('migrate', ['--database' => 'testbench'])->run();

    }

    /**
     * add the package provider
     *
     * @param $app
     * @return array
     */
    protected function getPackageProviders($app)
    {
        return [MyServiceProvider::class];
    }

    /**
     * Define environment setup.
     *
     * @param  \Illuminate\Foundation\Application  $app
     * @return void
     */
    protected function getEnvironmentSetUp($app)
    {
        // Setup default database to use sqlite :memory:
        $app['config']->set('database.default', 'testbench');
        $app['config']->set('database.connections.testbench', [
            'driver'   => 'sqlite',
            'database' => ':memory:',
            'prefix'   => '',
        ]);
    }
}

您可能还想阅读这篇博客文章


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接