ceb88ab102
Корень оказался в Laravel: в конце каждого теста он проверяет, осталось ли соединение в своей черновой транзакции, и если тест её закрыл сам - сбрасывает признак "база собрана". Следующий тест пересобирает базу целиком прямо посреди прогона, снося её под всеми остальными. В проекте полно кода со своими транзакциями, поэтому срабатывало примерно раз на восемь прогонов. Что сделано: - пересборка базы теперь один раз и в самом начале прогона, а не лениво в середине по первому файлу, который её закажет; - признак "собрано" держится взведённым - пересборка посреди прогона стала невозможна; - отказ заливки схемы стал громким: раньше PDO мог вернуть отказ без ошибки, и прогон ехал дальше по неполной схеме; - добавлена сверка полноты сборки: сколько шагов записано против того, сколько их лежит. Приёмка вырезанием: новый тест-сторож зелёный с защитой и падает без неё, прогон без защиты дольше на 12 секунд - это и есть лишняя пересборка. Замер до и после, полный набор портала: без правки 3175 прошло, 837 упало с правкой, прогон 1 3971 прошло, 19 упало с правкой, прогон 2 3971 прошло, 19 упало, списки совпали дословно Оставшиеся 19 - давние и не от базы: 11 падают на неверном токене Яндекса, одна на типе исключения, семь счётных от накопления данных между тестами. Плюс план перевода чтения вердикта и пересдачи на опрос - отдельным файлом, код по нему ещё не писался. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
42 lines
2.3 KiB
PHP
42 lines
2.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
/**
|
|
* Сторож против пересборки тестовой БД ПОСРЕДИ прогона.
|
|
*
|
|
* Laravel заворачивает каждый тест в «черновую» транзакцию, а в конце проверяет, что
|
|
* соединение в ней осталось. Если тест черновик закрыл сам, Laravel сбрасывает свой
|
|
* признак «БД собрана» (RefreshDatabase.php, строки 158-160) и следующий тест
|
|
* пересобирает базу целиком — посреди прогона, снося её под всеми остальными. Отсюда
|
|
* и «прогон рвётся через раз», и «таблица X не существует» за сотни шагов от причины.
|
|
*
|
|
* Tests\TestCase взводит признак на каждом тесте, поэтому пересборки не происходит.
|
|
*
|
|
* ПРИЁМКА ВЫРЕЗАНИЕМ: убрать строку `RefreshDatabaseState::$migrated = true;` из
|
|
* TestCase::setUpTraits() — второй тест этого файла обязан УПАСТЬ (метки не будет,
|
|
* потому что базу пересоберут между тестами). Вернуть строку — снова зелёный.
|
|
*/
|
|
it('ловушка: тест закрывает черновую транзакцию и оставляет метку в БД', function () {
|
|
// Именно так ведёт себя боевой код со своими DB::transaction/SET LOCAL —
|
|
// здесь мы воспроизводим это нарочно и в чистом виде.
|
|
DB::commit();
|
|
|
|
DB::statement('DROP TABLE IF EXISTS proverka_peresborki');
|
|
DB::statement('CREATE TABLE proverka_peresborki (x int)');
|
|
|
|
expect(Schema::hasTable('proverka_peresborki'))->toBeTrue();
|
|
});
|
|
|
|
it('метка на месте — значит пересборки посреди прогона не было', function () {
|
|
expect(Schema::hasTable('proverka_peresborki'))->toBeTrue();
|
|
|
|
DB::statement('DROP TABLE IF EXISTS proverka_peresborki');
|
|
});
|