LoginSignup
11

More than 3 years have passed since last update.

【Laravel】PHPUnitテスト用にSQLiteをDBに設定した際に気を付けるべきマイグレーションの記述と解決方法

Last updated at Posted at 2019-06-19

つらい思いをした

テストコードが破城しているプロジェクトのシステム(Laravel5.6)に対して、とりあえず正常にテストが走るようにリファクタしようと思い、
まずはテストのDBをSQLiteに設定して個々のテストコードを直そうと思った矢先、マイグレーションの書き方が不味かったらしく、
SQLiteの仕様でこけました
のでとりあえずマイグレーションの記述をSQLiteでも対応できるように直しました。

SQLiteは1回の変更でdropColumnrenameColumnを複数回呼び出すことはできない

どうやらSQLiteは1回の変更でdropColumnrenameColumnを複数回呼び出すことはできないらしい

ので以下のようにマイグレーションを記述していると、MySQLでは正常に処理されるがSQLiteではエラーが発生する

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class DeleteNameAndKanaOnUserTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('user', function (Blueprint $table) {
            $table->dropColumn('name');
            $table->dropColumn('kana');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('user', function (Blueprint $table) {
            $table->string('name');
            $table->string('kana');
        });
    }
}

以下エラー内容

BadMethodCallException: SQLite doesn't support multiple calls to dropColumn / renameColumn in a single modification.

なので複数の処理は以下のように修正する必要があります。

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class DeleteNameAndKanaOnUserTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('user', function (Blueprint $table) {
            $table->dropColumn('name');
        });
        Schema::table('user', function (Blueprint $table) {
            $table->dropColumn('kana');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('user', function (Blueprint $table) {
            $table->string('name');
        });
        Schema::table('user', function (Blueprint $table) {
            $table->string('kana');
        });
    }
}

テーブル作成時はNOT NULL制約を指定できるが、列追加する際はNOT NULL制約をつけることができない

テーブルを作成するときはNOT NULL制約をつけることはできるみたいですが、後で列を追加するときにNOT NULL制約をつけることはできないみたいです。

なので以下のように書いている場合、エラーが発生します。

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('user', function (Blueprint $table) {
            $table->string('hoge');
        });
        Schema::table('user', function (Blueprint $table) {
            $table->string('huga');
        });
    }

以下エラー内容

PDOException: SQLSTATE[HY000]: General error: 1 Cannot add a NOT NULL column with default value NULL

もしNOT NULL制約でない場合は以下のようにデフォルトでNULLを入れてやれば大丈夫のようです

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('user', function (Blueprint $table) {
            $table->string('hoge')->nullable();
        });
        Schema::table('user', function (Blueprint $table) {
            $table->string('huga')->nullable();
        });
    }

もしNOT NULL制約があるカラムの場合は以下のように一旦NULLを許可して、後でNOT NULL制約にする必要があるみたいです
(もっと他にやり方がありそうな気もしますが・・・)

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('user', function (Blueprint $table) {
            $table->string('tell')->nullable();
        });
        Schema::table('user', function (Blueprint $table) {
            $table->string('tell')->nullable(false)->change();
        });
    }

おわり

  • そもそもテストDBにSQLiteを設定するのがいいのかわからない・・・

参考URL

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11