데이터베이스 테스트
번역일: 2026년 6월 20일
데이터베이스 테스트
소개
Laravel은 데이터베이스를 사용하는 애플리케이션을 테스트할 때 유용한 도구와 어설션을 다양하게 제공합니다. 또한 모델 팩토리와 시더를 활용하면 Eloquent 모델과 관계를 이용해 테스트용 데이터를 손쉽게 생성할 수 있습니다. 이 문서에서는 이러한 기능들을 차례로 살펴봅니다.
각 테스트 후 데이터베이스 초기화
테스트를 작성할 때 가장 먼저 고려해야 할 것은 테스트 간 데이터 격리입니다. 이전 테스트에서 삽입한 데이터가 다음 테스트에 영향을 주지 않도록, Laravel에 내장된 Illuminate\Foundation\Testing\RefreshDatabase 트레이트를 사용하면 이 문제를 자동으로 처리할 수 있습니다.
테스트 클래스에 트레이트를 추가하기만 하면 됩니다.
Pest
<?php
use Illuminate\Foundation\Testing\RefreshDatabase;
pest()->use(RefreshDatabase::class);
test('기본 예제', function () {
$response = $this->get('/');
// ...
});PHPUnit
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ExampleTest extends TestCase
{
use RefreshDatabase;
/**
* 기본 기능 테스트 예제
*/
public function test_basic_example(): void
{
$response = $this->get('/');
// ...
}
}RefreshDatabase 트레이트는 데이터베이스 스키마가 이미 최신 상태라면 마이그레이션을 다시 실행하지 않습니다. 대신, 각 테스트를 데이터베이스 트랜잭션 안에서 실행하고 테스트가 끝나면 롤백합니다. 따라서 이 트레이트를 사용하지 않는 테스트 케이스에서 삽입된 레코드는 데이터베이스에 그대로 남을 수 있습니다.
NOTE
데이터베이스를 완전히 초기화하고 싶다면 Illuminate\Foundation\Testing\DatabaseMigrations 또는 Illuminate\Foundation\Testing\DatabaseTruncation 트레이트를 사용할 수 있습니다. 다만 두 옵션 모두 RefreshDatabase에 비해 실행 속도가 눈에 띄게 느립니다.
모델 팩토리
테스트를 실행하기 전에 데이터베이스에 샘플 레코드를 넣어야 하는 경우가 많습니다. 이때 컬럼 값을 하나씩 직접 지정하는 대신, 모델 팩토리를 사용하면 각 Eloquent 모델의 기본 속성값을 미리 정의해 두고 간편하게 재사용할 수 있습니다.
모델 팩토리를 만들고 활용하는 방법은 모델 팩토리 문서에서 자세히 확인할 수 있습니다. 팩토리를 정의한 뒤에는 테스트에서 다음과 같이 사용합니다.
Pest
use App\Models\User;
test('모델 인스턴스 생성', function () {
$user = User::factory()->create();
// ...
});PHPUnit
use App\Models\User;
public function test_models_can_be_instantiated(): void
{
$user = User::factory()->create();
// ...
}시더 실행
기능 테스트 중에 데이터베이스 시더를 사용해 초기 데이터를 채우고 싶다면 seed 메서드를 호출하면 됩니다. 기본적으로 seed 메서드는 DatabaseSeeder를 실행하며, 이 시더가 다른 모든 시더를 호출합니다. 특정 시더 클래스만 실행하려면 클래스명을 인수로 전달하세요.
Pest
<?php
use Database\Seeders\OrderStatusSeeder;
use Database\Seeders\TransactionStatusSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
pest()->use(RefreshDatabase::class);
test('주문 생성 가능', function () {
// DatabaseSeeder 전체 실행
$this->seed();
// 특정 시더만 실행
$this->seed(OrderStatusSeeder::class);
// ...
// 여러 시더를 배열로 지정해 실행
$this->seed([
OrderStatusSeeder::class,
TransactionStatusSeeder::class,
// ...
]);
});PHPUnit
<?php
namespace Tests\Feature;
use Database\Seeders\OrderStatusSeeder;
use Database\Seeders\TransactionStatusSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ExampleTest extends TestCase
{
use RefreshDatabase;
/**
* 새 주문 생성 테스트
*/
public function test_orders_can_be_created(): void
{
// DatabaseSeeder 전체 실행
$this->seed();
// 특정 시더만 실행
$this->seed(OrderStatusSeeder::class);
// ...
// 여러 시더를 배열로 지정해 실행
$this->seed([
OrderStatusSeeder::class,
TransactionStatusSeeder::class,
// ...
]);
}
}매 테스트마다 시더를 자동으로 실행하고 싶다면, 기본 테스트 클래스에 $seed 프로퍼티를 정의하면 됩니다. RefreshDatabase 트레이트를 사용하는 모든 테스트 전에 시더가 자동으로 실행됩니다.
<?php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
/**
* 각 테스트 전에 기본 시더를 실행할지 여부
*
* @var bool
*/
protected $seed = true;
}$seed가 true이면 각 테스트 전에 Database\Seeders\DatabaseSeeder가 실행됩니다. 특정 시더만 실행하고 싶다면 테스트 클래스에 $seeder 프로퍼티를 추가하세요.
use Database\Seeders\OrderStatusSeeder;
/**
* 각 테스트 전에 실행할 특정 시더
*
* @var string
*/
protected $seeder = OrderStatusSeeder::class;사용 가능한 어설션
Laravel은 Pest 또는 PHPUnit 기능 테스트에서 사용할 수 있는 다양한 데이터베이스 어설션을 제공합니다. 각 어설션을 아래에서 살펴봅니다.
assertDatabaseCount
테이블에 지정한 수만큼 레코드가 존재하는지 확인합니다.
$this->assertDatabaseCount('users', 5);assertDatabaseEmpty
테이블에 레코드가 하나도 없는지 확인합니다.
$this->assertDatabaseEmpty('users');assertDatabaseHas
테이블에 주어진 키/값 조건에 맞는 레코드가 존재하는지 확인합니다.
$this->assertDatabaseHas('users', [
'email' => 'sally@example.com',
]);assertDatabaseMissing
테이블에 주어진 키/값 조건에 맞는 레코드가 존재하지 않는지 확인합니다.
$this->assertDatabaseMissing('users', [
'email' => 'sally@example.com',
]);assertSoftDeleted
주어진 Eloquent 모델이 소프트 삭제(soft delete) 상태인지 확인합니다.
$this->assertSoftDeleted($user);assertNotSoftDeleted
주어진 Eloquent 모델이 소프트 삭제되지 않은 상태인지 확인합니다.
$this->assertNotSoftDeleted($user);assertModelExists
주어진 모델 또는 모델 컬렉션이 데이터베이스에 존재하는지 확인합니다.
use App\Models\User;
$user = User::factory()->create();
$this->assertModelExists($user);assertModelMissing
주어진 모델 또는 모델 컬렉션이 데이터베이스에 존재하지 않는지 확인합니다.
use App\Models\User;
$user = User::factory()->create();
$user->delete();
$this->assertModelMissing($user);expectsDatabaseQueryCount
테스트 중에 실행될 데이터베이스 쿼리의 총 횟수를 미리 지정합니다. 실제 실행된 쿼리 수가 예상값과 다르면 테스트가 실패합니다. N+1 문제 등 불필요한 쿼리 발생을 감지할 때 유용합니다.
$this->expectsDatabaseQueryCount(5);
// 테스트 코드...