在Laravel中设置PHPUnit测试

Phi*_*oss 9 php phpunit laravel laravel-5.1

我对单元测试很新,但我已经阅读了很多关于phpunit.de的文档(直到第10章).

它指出使用数据库进行测试可能很慢,但如果设置正确,它可以与非数据库测试一样快.

因此,我想在Laravel中测试一个模型.我已经创建了一个模型工厂来将数据植入数据库.

我也创建了一个基本测试.

在PHPUnits文档中,它声明在每次测试之前,setUp()调用该方法来设置测试.还有另一种静态方法setUpBeforeClass().

我想只为我的数据库表播种一次,并使用我的测试中的记录.所以我使用Laravels factory()函数从setUpBeforeClass()方法中为数据库设定种子.

这是我的代码:

class CommentTest extends TestCase
{
    protected static $blog;
    protected static $comments;

    public static function setUpBeforeClass()
    {
        parent::setUpBeforeClass();

        self::$blog = factory(App\Models\Content\Blog::class)->create();
        self::$comments = factory(App\Models\Content\Comment::class, 6)->create();
    }

    public function testSomething()
    {
        $this->assertTrue(true);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,当我运行时phpunit,我收到以下错误:

Fatal error: Call to a member function make() on a non-object in \vendor\laravel\framework\src\Illuminate\Foundation\helpers.php on line 54

Call Stack:
    0.0002     240752   1. {main}() \vendor\phpunit\phpunit\phpunit:0
    0.0173    1168632   2. PHPUnit_TextUI_Command::main() \vendor\phpunit\phpunit\phpunit:47
    0.0173    1175304   3. PHPUnit_TextUI_Command->run() \vendor\phpunit\phpunit\src\TextUI\Command.php:100
    2.9397    5869416   4. PHPUnit_TextUI_TestRunner->doRun() \vendor\phpunit\phpunit\src\TextUI\Command.php:149
    2.9447    6077272   5. PHPUnit_Framework_TestSuite->run() \vendor\phpunit\phpunit\src\TextUI\TestRunner.php:440
    2.9459    6092880   6. PHPUnit_Framework_TestSuite->run() \vendor\phpunit\phpunit\src\Framework\TestSuite.php:747
    2.9555    6096160   7. call_user_func:{\vendor\phpunit\phpunit\src\Framework\TestSuite.php:697}() \vendor\phpunit\phpunit\src\Framework\TestSuite.php:697
    2.9555    6096272   8. CommentTest::setUpBeforeClass() \vendor\phpunit\phpunit\src\Framework\TestSuite.php:697
    2.9555    6096480   9. factory() \tests\CommentTest.php:18
    2.9556    6096656  10. app() \vendor\laravel\framework\src\Illuminate\Foundation\helpers.php:350
Run Code Online (Sandbox Code Playgroud)

如果我将代码移动setUpBeforeClass()setUp()并运行它,它会按预期工作,但这肯定是低效的,因为它为每个测试播种数据库?

我的问题:

  1. 是否setUpBeforeClass()以正确的方式播种数据库?
  2. 如果是(问题1),那么为什么我在运行phpunit时会遇到致命错误,并且在调用之前我应该​​做些什么factory()
  3. 如果我必须将代码放在setUp()方法中,是否会出现性能问题?
  4. 应我甚至是从播种setUpBeforeClass()setUp()方法?在Laravels文档中,它显示了在测试中发生种子的示例,但是如果我正在运行100次测试(例如),播种100次是个好主意吗?

Phi*_*oss 19

好的,经过一些调查(类)后,我确定在调用静态setUpBeforeClass()方法时尚未创建Laravel应用程序.

Laravel容器是第一次setUp()调用时创建的\vendor\laravel\framework\src\illuminate\Foundation\Testing\TestCase.php.这就是我将代码移动到setUp()方法时工作正常的原因.

然后将容器存储在存储的$app属性中\vendor\laravel\framework\src\illuminate\Foundation\Testing\ApplicationTrait.php.

我可以通过将此代码添加到setUpBeforeClass()方法来手动创建容器实例:

$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
Run Code Online (Sandbox Code Playgroud)

但是这种方法看起来很糟糕,我不喜欢它.

相反,我将种子代码移动到setUp()方法,但只有在类属性为null时才播种数据库.因此它只会在第一次调用时播种setUp().任何后续电话都不会播种:

class CommentTest extends TestCase
{
    use DatabaseMigrations;

    protected static $blog;
    protected static $comments;

    public function setUp()
    {
        parent::setUp();

        $this->runDatabaseMigrations();

        if (is_null(self::$blog)) {
            self::$blog = factory(App\Models\Content\Blog::class, 1)->create();
            self::$comments = factory(App\Models\Content\Comment::class, 6)->create();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

结合Laravels DatabaseMigrations特性进行测试,现在是工作流程:

  1. 调用PHPUnit
  2. 调用Test类,其中包含DatabaseMigrations特征
  3. 迁移数据库(创建表)
  4. setUp()第一次调用该方法,该方法使用测试数据对相关表进行种子处理
  5. 运行测试,并访问测试数据
  6. 没有tearDown()调用方法,而是DatabaseMigrationstrait只是重置数据库,因此我的测试不必担心清理测试数据.

编辑

此外,似乎(虽然我不是100%),如果你有自定义setUp()方法,你需要runDatabaseMigrations()从重写setUp()方法手动调用:

public function setUp()
{
    parent::setUp();
    $this->runDatabaseMigrations();

    /** Rest of Setup **/
}
Run Code Online (Sandbox Code Playgroud)

runDatabaseMigrations()如果重载setUp()方法,似乎不会自动调用.

我希望这会有所帮助,但如果其他人有更好的解决方案,请随时告诉我:)

  • 我开始测试提到的 runDatabaseMigrations 问题,但正如指出的 https://github.com/laravel/framework/commit/231213d5f8ef9779e25af61dcedea0a0984b3cf9 它已在 5.2 中修复 (2认同)