Я довольно новичок в модульном тестировании, но я почти полностью прочитал всю документацию на phpunit.de (до главы 10).
В нем говорится, что тестирование с использованием баз данных может быть медленным, но при правильной настройке это может быть так же быстро, как тестирование без базы данных.
Поэтому я хочу протестировать модель в Laravel. Я создал фабрику модели для засева данных в базу данных.
Я также создал базовый тест.
В документации PHPUnits указано, что перед каждым тестом setUp()
метод setUp()
для настройки теста. Существует еще один статический метод setUpBeforeClass()
.
Я хочу выровнять таблицу базы данных только один раз и использовать записи в моем тесте. Поэтому я использовал функцию Laravels factory()
для setUpBeforeClass()
базы данных из метода 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); } }
Однако, когда я запускаю 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
Если я setUpBeforeClass()
код из setUpBeforeClass()
в setUp()
и запустим его, он будет работать так, как ожидалось, но, конечно же, это неэффективно, поскольку он посещает базу данных для каждого теста?
Мои вопросы:
setUpBeforeClass()
базу данных из setUpBeforeClass()
правильный способ сделать это? factory()
? setUp()
, будут ли проблемы с производительностью? setUp()
методы setUpBeforeClass()
или setUp()
? В документации Laravels приводятся примеры, где посев происходит в самом тесте, но если я выполняю 100 тестов (например), рекомендуется ли посещать 100 раз? Хорошо, после нескольких исследований (классов), я решил, что приложение Laravel еще не создано, когда setUpBeforeClass()
статический setUpBeforeClass()
.
Контейнер Laravel создается в первый раз, когда setUp()
вызывается в \vendor\laravel\framework\src\illuminate\Foundation\Testing\TestCase.php
. Вот почему он отлично работает, когда я setUp()
к 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();
Но этот метод кажется довольно взломанным, и мне это не нравится.
Вместо этого я переместил код посева в метод setUp
(), но только setUp
базу данных, если свойства класса были пустыми. Поэтому он setUp()
только при первом вызове 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(); } } }
В сочетании с характеристикой Laravels DatabaseMigrations
для тестирования, теперь это рабочий процесс:
DatabaseMigrations
setUp()
вызывается в первый раз, который семена соответствующих таблиц с данными тестирования tearDown()
, вместо этого свойство DatabaseMigrations
просто сбрасывает базу данных, поэтому мой тест не должен беспокоиться о очистке тестовых данных. РЕДАКТИРОВАТЬ
Кроме того, кажется (хотя я не 100%), что если у вас есть собственный setUp()
, вам нужно вручную вызвать runDatabaseMigrations()
из переопределенного setUp()
:
public function setUp() { parent::setUp(); $this->runDatabaseMigrations(); /** Rest of Setup **/ }
runDatabaseMigrations()
, похоже, не вызывается автоматически, если вы перегружаете метод setUp()
.
Я надеюсь, что это поможет, но если у кого-то еще есть лучшее решение, пожалуйста, сообщите мне 🙂