Миграция только один раз с сумраком Laravel
В соответствии с документацией "Тестирование базы данных" я могу сбрасывать базу данных после каждого теста (первый вариант). Второй вариант - запустить тест с использованием транзакций. Мне кажется, это лучший подход, но если я хочу запустить с транзакцией, миграция не запускается.
Есть ли способ запустить миграцию один раз для всего процесса тестирования?
Другими словами, я хочу запустить миграцию, выполнить все тесты с транзакцией, а затем выполнить откат. Я пытался с тем, что говорит документация, но я думаю, что-то не хватает.
3 ответа
Похоже на то, что сегодня мы сталкиваемся с этим сегодня, и запуск миграций в сочетании с миграциями, похоже, делает свое дело. Снимок моего теста выглядит следующим образом:
<?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 в сочетании с сумраком.
https://github.com/laravel/dusk/issues/110
Создание пользовательской записи и ее использование в браузере выполняется в двух разных процессах. Это означает, что созданный пользователь является частью транзакции базы данных, которая не зафиксирована и, следовательно, недоступна процессу браузера.
Миграция базы данных работает. Таким образом, вы должны использовать их. Также убедитесь, что вы используете отдельную тестовую базу данных, чтобы не связываться с вашей базой данных производства / разработки.
https://laravel.com/docs/5.4/dusk
Чтобы заставить Dusk использовать собственный файл среды при запуске тестов, создайте файл.env.dusk. {Environment} в корневом каталоге вашего проекта. Например, если вы будете инициировать команду dusk из своей локальной среды, вам следует создать файл.env.dusk.local.
При запуске тестов Dusk создаст резервную копию вашего файла.env и переименует вашу среду Dusk в.env. После завершения тестов ваш файл.env будет восстановлен.
Предоставленный ответ работает, потому что работают DatabaseMigrations. use DatabaseTransactions
не актуально.
Из того, что я понимаю, я не думаю, что транзакции могут когда-либо работать при использовании dusk, поскольку каждый запрос браузера в dusk создает отдельный экземпляр вашего приложения laravel.
Ранее phpunit создавал новое приложение в памяти как часть процесса (в setUp
/ createApplication
метод), затем протестируйте это тестовое приложение, затем уничтожьте его и настройте следующее. Таким образом, транзакции могут быть обернуты (или только внутри) в части создания и уничтожения этого приложения, прежде чем оно установит новое соединение с базой данных для следующего теста.
В сумерках это настоящее комплексное тестирование (включая браузер, фальшивое взаимодействие с пользователем, маршрутизацию на вашем локальном компьютере и т. Д.), Что означает, что не все содержится в среде, в которой выполняются ваши тесты, как они обычно в phpunit.
Сумерки делает следующее:
- Копирует ваш
.env.dusk.*
и запускает хромедрайвер (или любую другую подобную селену вещь, которую вы используете) - Запускает команду оболочки phpunit (т.е. новая команда, новый процесс)
- Команда phpunit запускает ваши сумерки, каждый из которых открывает окно браузера и делает запросы (каждый запрос запускает новый процесс php-fpm и php (для nginx)) - так же, как если бы вы делали эти запросы самостоятельно. Каждый из них имеет отдельные соединения с БД и поэтому не может взаимодействовать с транзакциями друг друга.
Стоит также отметить, что DatabaseTransactions
trait находится в пакете Foundation, а не в пакете Dusk, поэтому он не собирается / упаковывается с учетом Dusk.
Это также объясняет, почему 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
}
...