Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Diab's avatar
Level 5

Separate migration files for testing

Hi guys, I have a project with tons of migration files on hand (lots of modifications to the original table schemas kind of projects) that needs unit-testing coverage. So, after configuring the phpunit.xml file to use SQLite and running the test as expected SQLSTATE[HY000]: General error: 1 Cannot add a NOT NULL column with default value NULL (SQL: alter table "users" add column "role" varchar not null) error showed up. So, I've decided to create clean optimized migration files to be used by unit-testing only, and to accomplish this I've used this package: https://github.com/bennett-treptow/laravel-migration-generator

Then, I placed the generate files in Tests/database/migrations and overrode DatabaseMigrations & RefreshDatabase trait methods in the TestCase.php to point the migrations to the new path like so:

public function runDatabaseMigrations()
	{
		$this->artisan('migrate:fresh', [
			'--path' => 'tests/database/migrations',
		]);

		$this->app[Kernel::class]->setArtisan(null);

		$this->beforeApplicationDestroyed(function () {
			$this->artisan('migrate:rollback');

			RefreshDatabaseState::$migrated = false;
		});
	}

	protected function refreshTestDatabase()
	{
		if ( ! RefreshDatabaseState::$migrated)
		{
			$this->artisan('migrate:fresh', [
				'--path' => 'tests/database/migrations',
			]);

			$this->app[\Illuminate\Contracts\Console\Kernel::class]->setArtisan(null);

			RefreshDatabaseState::$migrated = true;
		}

		$this->beginDatabaseTransaction();
	}

But, this error was returned Cannot declare class X, because the name is already in use. Adding namespaces to those migration files will suppress this error but then it will start complaining that the class name is not the same as the migration file name.

Would appreciate it if someone can help out with an example or a workaround for this. Thanks!

0 likes
2 replies
martinbean's avatar

@diab Two things here:

  • You should not be using different migrations in tests than your application. You’re not testing your application if you’re testing different code.
  • A unit test shouldn’t need migrations in the first place. You’re not testing a unit of code in isolation if it needs a database, the framework, etc. This is an integration test.
Diab's avatar
Level 5

Hey @martinbean, thanks for the reply. As for the 1st point, the generated migration files by the mentioned package are from existing database structure that is being used by the application. Even future migration files get generated along with the default framework ones with no issues. The main reason behind using this approach is as described here:

Generate migrations from existing database structures, an alternative to the schema dump provided by Laravel. A primary use case for this package would be a project that has many migrations that alter tables using ->change() from doctrine/dbal that SQLite doesn't support and need a way to get table structures updated for SQLite to use in tests.

And yes, the goal is to cover the code with both unit and feature tests.

Please or to participate in this conversation.