본문 바로가기

Laravel

Laravel tests, RefreshDatabase

RefreshDatabase는 각각의 테스트가 서로 영향을 주지 않으면서 DB를 깨끗하게, 독립적으로 사용하기 위해 쓰인다.

 

라라벨에서의 테스트 생명 주기

PHPUnit과 유사하다.

  • 테스트 전에 각각 setUp 메서드가 실행된다
    • setUp()은 라라벨 앱을 생성하고 refresh한다.
    • traits를 설정한다.
    • afterApplicationCreatedCallbacks, sets up events, clears facade’s resolved instances 등을 호출한다.
  • 실제 테스트가 실행된다
  • 각각의 테스트가 종료될 때 tearDown 메서드가 실행된다.
    • beforeApplicationDestroyedCallbacks가 호출된다.
    • mockery를 종료하고 변수를 초기화 한다.

RefreshDatabase trait

테스트가 RefreshDatabase trait를 사용한다면 setUpTraits는 trait로부터 refreshDatabase()를 호출한다. 설정한 테스트 환경에 따라 테스트에서 인메모리 DB와 일반 DB를 쓸 수 있고 그에 맞게 DB를 refresh한다.

In Memory Database

인메모리 DB의 경우 그냥 DB를 migrate하고, 빠르다. 그러므로 각각의 테스트가 실행되기 전에 완료될 수 있다.

protected function refreshInMemoryDatabase()
{
	$this->artisan('migrate');

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

Regular Database

if (! RefreshDatabaseState::$migrated) {
	$this->artisan('migrate:fresh', [
      '--drop-views' => $this->shouldDropViews(),
      '--drop-types' => $this->shouldDropTypes(),
    ]);

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

	RefreshDatabaseState::$migrated = true;
}

DB가 이미 migrate됐다면 DB transaction을 시작한다.

foreach ($this->connectionsToTransact() as $name) {
    $connection = $database->connection($name);
    $dispatcher = $connection->getEventDispatcher();

    $connection->unsetEventDispatcher();
    $connection->beginTransaction();
    $connection->setEventDispatcher($dispatcher);
}

그리고 transaction이 roll back될 곳에 beforeApplicationDestroyed 콜백을 등록한다. 이 콜백들은 각각의 테스트가 끝날 때마다 tearDown 메서드 내에서 실행된다. 롤백은 테스트로 인해 DB가 변경되는 것을 막아주고 그로 인해 다음 테스트가 깨끗한 DB 상에서 실행될 수 있다.

$this->beforeApplicationDestroyed(function () use ($database) {
	foreach ($this->connectionsToTransact() as $name) {
		$connection = $database->connection($name);
		$dispatcher = $connection->getEventDispatcher();

		$connection->unsetEventDispatcher();
		$connection->rollback();
		$connection->setEventDispatcher($dispatcher);
		$connection->disconnect();
    }
});