使用 Laravel dusk 仅迁移一次

Migrate only once with Laravel dusk

根据to the "Database Testing" documentation,我可以在每次测试后重置数据库(第一个选项)。第二个选项是 运行 使用事务进行测试。这对我来说似乎是一种更好的方法,但如果我想 运行 使用事务,则迁移不会 运行。

有什么办法运行迁移一次所有测试过程?

换句话说,我想运行迁移,运行每次测试事务,然后回滚。我尝试了文档中所说的内容,但我认为缺少某些内容。

今天为此纠结了一段时间,运行将迁移与迁移结合使用似乎可以解决问题。我的测试截图如下:

<?php

namespace Tests\Browser;

use App\User;
use Tests\DuskTestCase;

use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;

class DefaultTest extends DuskTestCase
{
    use DatabaseMigrations, DatabaseTransactions;

    /**
     * A Dusk test example.
     *
     * @return void
     */
    public function test_something()
    {
        //Add test stuff here
    }
}

我在实际测试中有几个工厂,它们似乎 运行 通过迁移,测试后数据按预期销毁。

暂时无法 运行 DatabaseTransactions 与 dusk 结合使用。

https://github.com/laravel/dusk/issues/110

The creation of the user record and the use of it in the browser are done in two different processes. This means the created user is part of a database transaction which is not committed and thus not accessible by the browser process.

数据库迁移有效。所以你应该使用那些。还要确保你 运行 有一个单独的测试数据库,这样你就不会弄乱你的 production/development 数据库。

https://laravel.com/docs/5.4/dusk#environment-handling

To force Dusk to use its own environment file when running tests, create a .env.dusk.{environment} file in the root of your project. For example, if you will be initiating the dusk command from your local environment, you should create a .env.dusk.local file.

When running tests, Dusk will back-up your .env file and rename your Dusk environment to .env. Once the tests have completed, your .env file will be restored.

提供的答案有效,因为 DatabaseMigrations 有效。 use DatabaseTransactions 不相关。

据我所知,我认为使用 dusk 时事务永远无法工作,因为 dusk 中的每个浏览器请求都会创建一个单独的 laravel 应用程序实例。

以前,phpunit 会在内存中创建一个新的应用程序作为进程的一部分(在 setUp / createApplication 方法中),然后针对该测试应用程序进行测试,然后摧毁它并建立下一个。因此,在为下一次测试启动新的数据库连接之前,事务可以围绕(或只是在内部)该应用程序的创建和销毁部分。

使用 dusk,它是真正的 end-to-end 测试(包括浏览器、伪造的用户交互、本地计算机上的路由等),这意味着它并不全部包含在环境中你的测试在 运行 中,就像它们通常在 phpunit.

中一样

Dusk 执行以下操作:

  • 复制您的 .env.dusk.* 并启动 chromedriver(或您使用的任何 selenium-like 东西)
  • 触发一个php单元shell命令(即新命令,新进程)
  • phpunit 命令运行您的 dusk 测试,每个测试打开一个浏览器 window 并发出请求(每个请求开始一个新的 php-fpm 和 php process (for nginx)) - 就像你自己提出这些请求一样。他们每个人都有单独的数据库连接,因此不能与彼此的事务交互。

同样值得注意的是 DatabaseTransactions trait 在 Foundation 包中,而不是 Dusk 包中,因此在构建/打包时没有考虑 Dusk。

这也解释了为什么 in-memory sqlite 不能与 dusk 一起工作,因为一个进程无法访问另一个进程的内存。

这里有一个非常便携和可重用的方式:

abstract class DuskTestCase extends BaseTestCase {

   ...

    /**
     * @param int $batchCounter
     * @param string $className
     * @param int $threshold
     */
    public function refreshDb(&$batchCounter, $className = '', $threshold = 0) {
        if ($batchCounter <= $threshold) {
            //TODO: Here is where you'll want to run migrations and seeds and whatnot.
            $batchCounter++;
            $this->consoleOutput(trim($className . ' called refreshAndSeedTestingDb and $batchCounter++. $batchCounter=' . $batchCounter));
        }
    }

   /**
    * @param string $msg
    */
   public function consoleOutput($msg) {
       Log::debug($msg);
       $output = new \Symfony\Component\Console\Output\ConsoleOutput();
       $output->writeln($msg);
   }

然后在每个测试文件中:

class ExampleBrowserTest extends DuskTestCase {

    protected static $countDbRefreshed = 0;

    public function setUp() {//runs before every test function in this class
        parent::setUp();
        $this->refreshDb(self::$countDbRefreshed, __CLASS__); //inside uses a property to run only once per class
    }
...