因为测试不好,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=] 你正在与.