因为测试不好,phpunit in laravel?
because the test doesn't work well, phpunit in laravel?
我有以下设置:
config/database.php
具体在:'connections'
'testing' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('TEST_DB_HOST'),
'port' => env('TEST_DB_PORT', '5432'),
'database' => env('TEST_DB_DATABASE', 'forge'),
'username' => env('TEST_DB_USERNAME', 'forge'),
'password' => env('TEST_DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
'schema' => 'public',
'sslmode' => 'prefer'
],
在 .env 中
TEST_DB_CONECTION=testing
TEST_DB_HOST=mysql-db
TEST_DB_PORT=3306
TEST_DB_DATABASE=db_test
TEST_DB_USERNAME=root
TEST_DB_PASSWORD=secret_test
我所有的文件phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="true"
stopOnFailure="false">
<testsuites>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app</directory>
</whitelist>
</filter>
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
<env name="MAIL_DRIVER" value="array"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value="db_test"/>
</php>
</phpunit>
在我的测试中 class
use RefreshDatabase;
protected $user;
public function setUp() : void {
parent::setUp();
$this->user = factory(User::class)->create();
$this->actingAs($this->user);
}
public function testCreateExcessCarriers(){
var_dump("some text to try");
}
执行时:
docker-compose exec utraq vendor/bin/phpunit tests/Unit/Http/Controllers/ECControllerTest.php --filter testCreateExcessCarriers
我得到这个错误:
Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 1
Cannot add a NOT NULL column with default value NULL (SQL: alter table
"users" add column "agency_id" integer not null)
这样我就配置好了工厂,用模型检查一切正常
$factory->define(App\Models\User::class, function (Faker $faker) {
static $password;
return [
'uuid' => $faker->uuid,
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => $password ?: $password = bcrypt('secret'),
'active' => 1,
'agency_id' => 3,
];
});
但是我不知道为什么在执行命令后会出现该错误。我该如何更正它?
编辑:
我想我得到错误的迁移。对于用户 table,有 2 次迁移。
迁移 1:
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid');
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->string('address1')->nullable(); //Address 1
$table->string('address2')->nullable(); //Address 2
$table->string('city')->nullable(); //City
$table->string('state_name')->nullable(); //State
$table->integer('state_id')->nullable(); //State
$table->string('zip_code', 10)->nullable(); //Zip Code
$table->string('employee_type')->nullable();
$table->dateTime('last_logged_in')->nullable();
$table->json('dashboard')->nullable();
$table->rememberToken();
$table->timestamps();
});
迁移 2:如您所见,这是分配 agency_id
字段的地方
Schema::table('users', function (Blueprint $table) {
$table->integer('agency_id')->after('password');
$table->boolean('active')->after('remember_token')->default('0');
$table->boolean('verified')->after('active')->default(false);
$table->string('avatar')->nullable();
});
参考这个答案;
It seems SQLite simply leaves you in a bad state if you need to add a non-nullable column to an existing table, which column should also not have a default value
简而言之,您有 3 种可能来解决问题;
- 使用您在生产中使用的相同数据库 引擎 运行 您的测试。它速度较慢,但如果有任何问题,您肯定会看到相同的问题。
- 更改为可为空:
$table->integer('agency_id')->nullable()->after('password');
- (我绝对不推荐,因为它是外键)添加默认值:
$table->integer('agency_id')->default(1)->after('password');
根据你的问题,我想你实际上想使用你定义为“测试”连接的 mysql 测试数据库。
但是在你的 phpunint 配置中你使用了
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value="db_test"/>
这显然与 sqlite 连接有关。其他人已经指出了 sqlite 和添加不可空列的问题
您可能想要将连接更改为并删除 DB_DATABASE 条目
<env name="DB_CONNECTION" value="testing"/>
编辑:
TEST_DB_CONECTION=testing
好像哪里都用不到?还有一个错字 :) - 也可以从你的环境中删除
根据我的经验,这归结为 sqlite 的一个限制,无法在没有默认值的情况下将 non-nullable 列添加到现有的 table。
我们使用的 work-around 是将迁移拆分为同一个迁移中的 2 个步骤。第一步将列添加为可为空,下一步将其更新为 non-nullable.
所以您的迁移看起来像这样(未经测试):
Schema::table('users', function (Blueprint $table) {
$table->integer('agency_id')->nullable()->after('password');
});
Schema::table('users', function (Blueprint $table) {
$table->integer('agency_id')->nullable(false)->change();
});
原则上这是我们使用的,但可能不适用于所有用例。如果这更适合您的用例,您可能希望在第一步中设置默认值而不是使其可为空。
如果我没记错的话 nullable(false)
中的 false 参数后来才在 Laravel 5.x 中可用,所以根据 [= 的版本,这可能不起作用28=] 你正在与.
我有以下设置:
config/database.php
具体在:'connections'
'testing' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('TEST_DB_HOST'),
'port' => env('TEST_DB_PORT', '5432'),
'database' => env('TEST_DB_DATABASE', 'forge'),
'username' => env('TEST_DB_USERNAME', 'forge'),
'password' => env('TEST_DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
'schema' => 'public',
'sslmode' => 'prefer'
],
在 .env 中
TEST_DB_CONECTION=testing
TEST_DB_HOST=mysql-db
TEST_DB_PORT=3306
TEST_DB_DATABASE=db_test
TEST_DB_USERNAME=root
TEST_DB_PASSWORD=secret_test
我所有的文件phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="true"
stopOnFailure="false">
<testsuites>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app</directory>
</whitelist>
</filter>
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
<env name="MAIL_DRIVER" value="array"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value="db_test"/>
</php>
</phpunit>
在我的测试中 class
use RefreshDatabase;
protected $user;
public function setUp() : void {
parent::setUp();
$this->user = factory(User::class)->create();
$this->actingAs($this->user);
}
public function testCreateExcessCarriers(){
var_dump("some text to try");
}
执行时:
docker-compose exec utraq vendor/bin/phpunit tests/Unit/Http/Controllers/ECControllerTest.php --filter testCreateExcessCarriers
我得到这个错误:
Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 1 Cannot add a NOT NULL column with default value NULL (SQL: alter table "users" add column "agency_id" integer not null)
这样我就配置好了工厂,用模型检查一切正常
$factory->define(App\Models\User::class, function (Faker $faker) {
static $password;
return [
'uuid' => $faker->uuid,
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => $password ?: $password = bcrypt('secret'),
'active' => 1,
'agency_id' => 3,
];
});
但是我不知道为什么在执行命令后会出现该错误。我该如何更正它?
编辑: 我想我得到错误的迁移。对于用户 table,有 2 次迁移。
迁移 1:
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid');
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->string('address1')->nullable(); //Address 1
$table->string('address2')->nullable(); //Address 2
$table->string('city')->nullable(); //City
$table->string('state_name')->nullable(); //State
$table->integer('state_id')->nullable(); //State
$table->string('zip_code', 10)->nullable(); //Zip Code
$table->string('employee_type')->nullable();
$table->dateTime('last_logged_in')->nullable();
$table->json('dashboard')->nullable();
$table->rememberToken();
$table->timestamps();
});
迁移 2:如您所见,这是分配 agency_id
字段的地方
Schema::table('users', function (Blueprint $table) {
$table->integer('agency_id')->after('password');
$table->boolean('active')->after('remember_token')->default('0');
$table->boolean('verified')->after('active')->default(false);
$table->string('avatar')->nullable();
});
参考这个答案;
It seems SQLite simply leaves you in a bad state if you need to add a non-nullable column to an existing table, which column should also not have a default value
简而言之,您有 3 种可能来解决问题;
- 使用您在生产中使用的相同数据库 引擎 运行 您的测试。它速度较慢,但如果有任何问题,您肯定会看到相同的问题。
- 更改为可为空:
$table->integer('agency_id')->nullable()->after('password');
- (我绝对不推荐,因为它是外键)添加默认值:
$table->integer('agency_id')->default(1)->after('password');
根据你的问题,我想你实际上想使用你定义为“测试”连接的 mysql 测试数据库。
但是在你的 phpunint 配置中你使用了
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value="db_test"/>
这显然与 sqlite 连接有关。其他人已经指出了 sqlite 和添加不可空列的问题
您可能想要将连接更改为并删除 DB_DATABASE 条目
<env name="DB_CONNECTION" value="testing"/>
编辑:
TEST_DB_CONECTION=testing
好像哪里都用不到?还有一个错字 :) - 也可以从你的环境中删除
根据我的经验,这归结为 sqlite 的一个限制,无法在没有默认值的情况下将 non-nullable 列添加到现有的 table。
我们使用的 work-around 是将迁移拆分为同一个迁移中的 2 个步骤。第一步将列添加为可为空,下一步将其更新为 non-nullable.
所以您的迁移看起来像这样(未经测试):
Schema::table('users', function (Blueprint $table) {
$table->integer('agency_id')->nullable()->after('password');
});
Schema::table('users', function (Blueprint $table) {
$table->integer('agency_id')->nullable(false)->change();
});
原则上这是我们使用的,但可能不适用于所有用例。如果这更适合您的用例,您可能希望在第一步中设置默认值而不是使其可为空。
如果我没记错的话 nullable(false)
中的 false 参数后来才在 Laravel 5.x 中可用,所以根据 [= 的版本,这可能不起作用28=] 你正在与.