根据“数据库测试”文档,我可以在每次测试后重置数据库(第一个选项)。第二种选择是使用事务运行测试。这对我来说似乎是一种更好的方法,但如果我想使用事务运行,迁移不会运行。
有没有办法为所有测试过程运行一次迁移?
换句话说,我想运行迁移,使用事务运行每个测试,然后回滚。我尝试了文档所说的内容,但我认为缺少一些东西。
根据“数据库测试”文档,我可以在每次测试后重置数据库(第一个选项)。第二种选择是使用事务运行测试。这对我来说似乎是一种更好的方法,但如果我想使用事务运行,迁移不会运行。
有没有办法为所有测试过程运行一次迁移?
换句话说,我想运行迁移,使用事务运行每个测试,然后回滚。我尝试了文档所说的内容,但我认为缺少一些东西。
暂时无法结合黄昏运行 DatabaseTransactions。
https://github.com/laravel/dusk/issues/110
用户记录的创建和在浏览器中的使用是在两个不同的过程中完成的。这意味着创建的用户是未提交的数据库事务的一部分,因此浏览器进程无法访问。
数据库迁移工作。所以你应该使用那些。还要确保你运行一个单独的测试数据库,这样你就不会弄乱你的生产/开发数据库。
https://laravel.com/docs/5.4/dusk#environment-handling
要在运行测试时强制 Dusk 使用自己的环境文件,请在项目的根目录中创建一个 .env.dusk.{environment} 文件。例如,如果您要从本地环境启动黄昏命令,您应该创建一个 .env.dusk.local 文件。
运行测试时,Dusk 将备份您的 .env 文件并将您的 Dusk 环境重命名为 .env。测试完成后,您的 .env 文件将被恢复。
提供的答案有效,因为 DatabaseMigrations 有效。use DatabaseTransactions
不相关。
今天为此争论了一段时间,并且与迁移一起运行迁移似乎可以解决问题。我的测试快照如下:
<?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
}
}
在我的实际测试中,我有几个工厂,它们似乎在迁移过程中运行,数据在测试后按预期被破坏。
据我了解,我认为使用黄昏时事务永远无法工作,因为黄昏时的每个浏览器请求都会创建一个单独的 laravel 应用程序实例。
以前,phpunit 会在内存中创建一个新应用程序作为进程的一部分(在setUp
/createApplication
方法中),然后针对该测试应用程序进行测试,然后销毁它并设置下一个应用程序。因此,在为下一次测试启动新的数据库连接之前,可以将事务包装在该应用程序的创建和销毁部分周围(或仅在其内部)。
使用黄昏,它是真正的端到端测试(包括浏览器、伪造的用户交互、本地机器上的路由等),这意味着它并不全部包含在运行测试的环境中,就像它们一样通常在 phpunit 中。
黄昏执行以下操作:
.env.dusk.*
并启动 chromedriver(或您使用的任何类似硒的东西)还值得注意的是,该DatabaseTransactions
trait 位于 Foundation 包中,而不是 Dusk 包中,因此在构建/打包时并未考虑到 Dusk。
这也解释了为什么内存中的 sqlite 不适用于黄昏,因为一个进程无法访问另一个进程的内存。
这是一种非常便携和可重用的方式:
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
}
...