Laravelプロジェクトでテスト環境をセットアップしようとしています。使用しています http://packalyst.com/packages/package/mayconbordin/l5-fixtures メモリデータベースにsqliteをシードして呼び出すためのjsonを使用:
Artisan::call('migrate');
Artisan::call('db:seed');
私のsetUp関数では、これは、このプロジェクトで数千に達する可能性のあるすべてのテストの前に実行されます。
setUpBeforeClassを試しましたが、機能しませんでした。 createApplicationメソッドがすべてのテストで呼び出され、アプリケーション全体がリセットされ、おそらくjsonからフィクスチャが読み込まれなかったためだと思います。同じ理由。
これは、他の誰かが同じことに苦労している場合に備えて、私がそれを行った方法です。Laravelから継承する基本のtestClase
クラスを作成し、これを行いました。
_/**
* Creates the application.
*
* @return \Illuminate\Foundation\Application
*/
public function createApplication()
{
return self::initialize();
}
private static $configurationApp = null;
public static function initialize(){
if(is_null(self::$configurationApp)){
$app = require __DIR__.'/../bootstrap/app.php';
$app->loadEnvironmentFrom('.env.testing');
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
if (config('database.default') == 'sqlite') {
$db = app()->make('db');
$db->connection()->getPdo()->exec("pragma foreign_keys=1");
}
Artisan::call('migrate');
Artisan::call('db:seed');
self::$configurationApp = $app;
return $app;
}
return self::$configurationApp;
}
public function tearDown()
{
if ($this->app) {
foreach ($this->beforeApplicationDestroyedCallbacks as $callback) {
call_user_func($callback);
}
}
$this->setUpHasRun = false;
if (property_exists($this, 'serverVariables')) {
$this->serverVariables = [];
}
if (class_exists('Mockery')) {
Mockery::close();
}
$this->afterApplicationCreatedCallbacks = [];
$this->beforeApplicationDestroyedCallbacks = [];
}
_
createApplication()
メソッドとtearDown()
メソッドを上書きしました。同じ_$app
_構成を使用するように最初の構成を変更し、_$this->app
_をフラッシュするteardown()
の部分を削除しました。
私のテストの他のすべては、このTestClassから継承する必要があり、それだけです。
他のすべては機能しませんでした。これはインメモリデータベースでも機能し、100倍高速です。
ユーザーセッションを処理している場合は、ユーザーをログインしたら、破棄してログアウトする必要があります。そうしないと、アプリ環境が再構築されないため、ユーザーがログインするか、このようなものを追加してアプリケーションを更新できます。あなたが望むたびに:
_protected static $applicationRefreshed = false;
/**
* Refresh the application instance.
*
* @return void
*/
protected function forceRefreshApplication() {
if (!is_null($this->app)) {
$this->app->flush();
}
$this->app = null;
self::$configurationApp = null;
self::$applicationRefreshed = true;
parent::refreshApplication();
}
_
そして、これを_$this->setUphasRun = false;
_の前のtearDown()
に追加します。
_if (self::$applicationRefreshed) {
self::$applicationRefreshed = false;
$this->app->flush();
$this->app = null;
self::$configurationApp = null;
}
_
このコンテンツを使用してプロジェクトtestrunner
にファイルを作成します(テスト環境変数を使用して.env.testing
ファイルも準備します):
php artisan migrate:rollback --env=testing
php artisan migrate --env=testing --seed
vendor/bin/phpunit
そして、コマンドchmod +x testrunner
で実行する権限を与え、./testrunner
で実行します。それで全部です :)
上記のソリューションの主なアプローチは、すべてのテストに対してすべての移行を実行することです。テストごとに実行する移行とシードを指定するアプローチが好きです。
これにより、テストのタイミングが約70%短縮される可能性があるため、大規模なプロジェクトではより価値がある可能性があります(前述のようにsqliteインメモリDBを使用)。小さなプロジェクトの場合、それは多分少し面倒です。とにかく...
TestCaseでこれらを使用します。
/**
* Runs migrations for individual tests
*
* @param array $migrations
* @return void
*/
public function migrate(array $migrations = [])
{
$path = database_path('migrations');
$migrator = app()->make('migrator');
$migrator->getRepository()->createRepository();
$files = $migrator->getMigrationFiles($path);
if (!empty($migrations)) {
$files = collect($files)->filter(
function ($value, $key) use ($migrations) {
if (in_array($key, $migrations)) {
return [$key => $value];
}
}
)->all();
}
$migrator->requireFiles($files);
$migrator->runPending($files);
}
/**
* Runs some or all seeds
*
* @param string $seed
* @return void
*/
public function seed(string $seed = '')
{
$command = "db:seed";
if (empty($seed)) {
Artisan::call($command);
} else {
Artisan::call($command, ['--class' => $seed]);
}
}
次に、個々のテストで必要に応じて、migrate()とシードを呼び出します。例:
$this->migrate(
[
'2013_10_11_081829_create_users_table',
]
);
$this->seed(UserTableSeeder::class);
移行とシードを使用してデータベースをセットアップしてから、データベーストランザクションを使用するのはどうですか? ( https://laravel.com/docs/5.1/testing#resetting-the-database-after-each-test )
次のような職人を介してテストデータベースを設定できるようにしたかったのです。
$ php artisan migrate --database=mysql_testing
$ php artisan db:seed --database=mysql_testing
ご想像のとおり、私はmysqlを使用していますが、これがsqliteで機能しない理由がわかりません。これが私のやり方です。
config/database.php
まず、現在のデータベース情報の下にあるconfig /database.phpファイルにテストデータベース情報を追加します。
'connections' => [
'mysql' => [
'driver' => 'mysql',
'Host' => env('DB_Host', 'localhost'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
'mysql_testing' => [
'driver' => 'mysql',
'Host' => env('DB_Host', 'localhost'),
'database' => env('DB_TEST_DATABASE'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
],
このようにする場合は、DB_TEST_DATABASEを。envファイルに追加することを忘れないでください。
DB_DATABASE=abc
DB_TEST_DATABASE=abc_test
phpunit.xml
.envファイルで指定された上書き値の下でphpunit.xmlファイルに設定された値。したがって、phpunitに「mysql」データベース接続の代わりに「mysql_testing」データベース接続を使用するように指示します。
<?xml version="1.0" encoding="UTF-8"?>
<phpunit>
...
<php>
...
<env name="DB_CONNECTION" value="mysql_testing"/>
</php>
テストクラス
私のテストクラスは次のようになります。
class MyTest extends \TestCase
{
use \Illuminate\Foundation\Testing\DatabaseTransactions;
public function testSomething()
{
ここでは、すべてのテストの前にデータベースがリセットされるため、オプション1を選択します。ただし、データベースを希望どおりに機能させることができる場合があります。
私は以前にこれを一度試しました、そしてそれはあなたのために働くかもしれません。
tests/TestCase.phpテストケースを拡張して、新しい.envファイル.env.testingをロードします
<?php
class TestCase extends Illuminate\Foundation\Testing\TestCase
{
/**
* The base URL to use while testing the application.
*
* @var string
*/
protected $baseUrl = 'http://localhost';
/**
* Creates the application.
*
* @return \Illuminate\Foundation\Application
*/
public function createApplication()
{
/** @var $app \Illuminate\Foundation\Application */
$app = require __DIR__.'/../bootstrap/app.php';
$app->loadEnvironmentFrom('.env.testing');
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
return $app;
}
}
。env.testing
この新しい.envファイルを作成し、データベースの詳細を追加します
APP_ENV=testing
APP_DEBUG=true
APP_KEY=xxx
DB_CONNECTION=mysql
DB_Host=127.0.0.1
DB_DATABASE=abc_testing
DB_USERNAME=xxx
DB_PASSWORD=xxx
テストクラス:
PDOを使用して、データベースを削除して再作成します。すべてを切り捨てるよりも簡単です。次に、職人を使用してデータベースを移行およびシードします。
class MyTest extends TestCase
{
public static function setUpBeforeClass()
{
$config = parse_ini_file(".env.testing");
$username = $config['DB_USERNAME'];
$password = $config['DB_PASSWORD'];
$database = $config['DB_DATABASE'];
$Host = $config['DB_Host'];
// Create test database
$connection = new PDO("mysql:Host={$Host}", $username, $password);
$connection->query("DROP DATABASE IF EXISTS " . $database);
$connection->query("CREATE DATABASE " . $database);
}
public function testHomePage()
{
Artisan::call('migrate');
Artisan::call('db:seed');
$this->visit('/')
->see('Home')
->see('Please sign in')
->dontSee('Logout');
}