> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 데이터베이스 테스트

> RefreshDatabase·시더·팩토리·전용 어서션으로 Laravel의 DB 테스트를 효율적으로 작성하는 방법

## 소개

Laravel에는 데이터베이스를 사용하는 기능을 안전하고 빠르게 검증하기 위한 구조가 기본으로 제공됩니다. 데이터베이스 리셋용 트레이트, 모델 팩토리, 시더, 전용 어서션을 조합하면 잘 부러지지 않는 테스트를 작성할 수 있습니다.

먼저 `RefreshDatabase`를 사용하는 것이 기본입니다. 대부분의 경우 완전 리셋보다 빠르게 테스트의 독립성을 유지할 수 있습니다.

## 각 테스트 후 데이터베이스 리셋

이전 테스트 데이터가 다음 테스트에 영향을 주지 않도록 Laravel의 데이터베이스 리셋용 트레이트를 이용합니다.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  use Illuminate\Foundation\Testing\RefreshDatabase;

  uses(RefreshDatabase::class);

  test('기본 예시', function () {
      $response = $this->get('/');

      $response->assertOk();
  });
  ```

  ```php PHPUnit theme={null}
  <?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('/');

          $response->assertOk();
      }
  }
  ```
</CodeGroup>

`RefreshDatabase`는 스키마가 최신인지를 판정합니다. 최신이면 트랜잭션으로 테스트를 실행하고, 최신이 아니면 먼저 마이그레이션을 실행합니다.

```mermaid theme={null}
flowchart TD
    A[RefreshDatabase를 사용하는 테스트 시작] --> B{스키마는 최신인가?}
    B -- 예 --> C[DB 트랜잭션으로 실행]
    B -- 아니오 --> D[마이그레이션 실행]
    D --> E[테스트 실행]
    C --> E[테스트 실행]
    E --> F[롤백 / 상태 리셋]
```

트랜잭션 방식이 아니라, 매번 완전히 리셋하고 싶은 경우에는 다음 트레이트를 사용합니다.

| 트레이트                 | 동작                            | 사용 상황                                |
| -------------------- | ----------------------------- | ------------------------------------ |
| `RefreshDatabase`    | 스키마가 최신이면 트랜잭션, 필요할 때만 마이그레이션 | 일반적으로 이것을 첫 번째 후보로 삼는다               |
| `DatabaseMigrations` | 각 테스트마다 마이그레이션을 실행            | 매번 마이그레이션 라이프사이클을 거치고 싶은 경우          |
| `DatabaseTruncation` | 테이블을 TRUNCATE해서 초기화           | 트랜잭션이 적합하지 않은 환경에서 전체 데이터를 지우고 싶은 경우 |

## 모델 팩토리

테스트 전에 데이터를 준비할 때 모델 팩토리를 사용하면 Eloquent 모델을 간결하게 생성할 수 있습니다.

팩토리 정의·state·관계의 자세한 내용은 [Eloquent 팩토리](/ko/eloquent-factories)를 참조해 주세요.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  use App\Models\User;

  test('모델을 생성할 수 있다', function () {
      $user = User::factory()->create();

      expect($user->exists)->toBeTrue();
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use App\Models\User;
  use Tests\TestCase;

  class UserFactoryTest extends TestCase
  {
      public function test_models_can_be_instantiated(): void
      {
          $user = User::factory()->create();

          $this->assertTrue($user->exists);
      }
  }
  ```
</CodeGroup>

## 시더 실행

테스트 중에 데이터를 투입하고 싶은 경우에는 `seed()`를 사용합니다. 인수 없이 호출하면 `DatabaseSeeder`, 인수를 넣으면 특정 시더(또는 배열)를 실행할 수 있습니다.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  use Database\Seeders\OrderStatusSeeder;
  use Database\Seeders\TransactionStatusSeeder;
  use Illuminate\Foundation\Testing\RefreshDatabase;

  uses(RefreshDatabase::class);

  test('주문을 생성할 수 있다', function () {
      $this->seed();

      $this->seed(OrderStatusSeeder::class);

      $this->seed([
          OrderStatusSeeder::class,
          TransactionStatusSeeder::class,
      ]);

      // ...
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Database\Seeders\OrderStatusSeeder;
  use Database\Seeders\TransactionStatusSeeder;
  use Illuminate\Foundation\Testing\RefreshDatabase;
  use Tests\TestCase;

  class OrderTest extends TestCase
  {
      use RefreshDatabase;

      public function test_orders_can_be_created(): void
      {
          $this->seed();

          $this->seed(OrderStatusSeeder::class);

          $this->seed([
              OrderStatusSeeder::class,
              TransactionStatusSeeder::class,
          ]);

          // ...
      }
  }
  ```
</CodeGroup>

`RefreshDatabase`를 사용하는 모든 테스트에서 매번 자동 시드하고 싶은 경우에는 기저 테스트 클래스에 `#[Seed]` 애트리뷰트를 붙입니다.

```php theme={null}
<?php

namespace Tests;

use Illuminate\Foundation\Testing\Attributes\Seed;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

#[Seed]
abstract class TestCase extends BaseTestCase
{
}
```

특정 시더만 자동 실행하고 싶은 경우에는 `#[Seeder(...)]`를 사용합니다.

```php theme={null}
<?php

namespace Tests\Feature;

use Database\Seeders\OrderStatusSeeder;
use Illuminate\Foundation\Testing\Attributes\Seeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

#[Seeder(OrderStatusSeeder::class)]
class OrderStatusTest extends TestCase
{
    use RefreshDatabase;
}
```

## 사용 가능한 어서션

Laravel에는 Pest / PHPUnit 어느 쪽에서도 사용할 수 있는 데이터베이스 전용 어서션이 준비되어 있습니다.

### `assertDatabaseCount`

테이블 내의 레코드 건수가 기대값과 일치하는지 확인합니다.

<CodeGroup>
  ```php Pest theme={null}
  $this->assertDatabaseCount('users', 5);
  ```

  ```php PHPUnit theme={null}
  $this->assertDatabaseCount('users', 5);
  ```
</CodeGroup>

### `assertDatabaseEmpty`

테이블이 비어 있는지 확인합니다.

<CodeGroup>
  ```php Pest theme={null}
  $this->assertDatabaseEmpty('users');
  ```

  ```php PHPUnit theme={null}
  $this->assertDatabaseEmpty('users');
  ```
</CodeGroup>

### `assertDatabaseHas`

지정한 조건에 일치하는 레코드가 존재하는지 확인합니다.

<CodeGroup>
  ```php Pest theme={null}
  $this->assertDatabaseHas('users', [
      'email' => 'sally@example.com',
  ]);
  ```

  ```php PHPUnit theme={null}
  $this->assertDatabaseHas('users', [
      'email' => 'sally@example.com',
  ]);
  ```
</CodeGroup>

### `assertDatabaseMissing`

지정한 조건에 일치하는 레코드가 존재하지 않는지 확인합니다.

<CodeGroup>
  ```php Pest theme={null}
  $this->assertDatabaseMissing('users', [
      'email' => 'sally@example.com',
  ]);
  ```

  ```php PHPUnit theme={null}
  $this->assertDatabaseMissing('users', [
      'email' => 'sally@example.com',
  ]);
  ```
</CodeGroup>

### `assertSoftDeleted`

대상 Eloquent 모델이 소프트 삭제된 상태인지 확인합니다.

<CodeGroup>
  ```php Pest theme={null}
  $this->assertSoftDeleted($user);
  ```

  ```php PHPUnit theme={null}
  $this->assertSoftDeleted($user);
  ```
</CodeGroup>

### `assertNotSoftDeleted`

대상 Eloquent 모델이 소프트 삭제되지 않았는지 확인합니다.

<CodeGroup>
  ```php Pest theme={null}
  $this->assertNotSoftDeleted($user);
  ```

  ```php PHPUnit theme={null}
  $this->assertNotSoftDeleted($user);
  ```
</CodeGroup>

### `assertModelExists`

지정한 모델(또는 모델 컬렉션)이 DB에 존재하는지 확인합니다.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  use App\Models\User;

  $user = User::factory()->create();

  $this->assertModelExists($user);
  ```

  ```php PHPUnit theme={null}
  <?php

  use App\Models\User;

  $user = User::factory()->create();

  $this->assertModelExists($user);
  ```
</CodeGroup>

### `assertModelMissing`

지정한 모델(또는 모델 컬렉션)이 DB에 존재하지 않는지 확인합니다.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  use App\Models\User;

  $user = User::factory()->create();
  $user->delete();

  $this->assertModelMissing($user);
  ```

  ```php PHPUnit theme={null}
  <?php

  use App\Models\User;

  $user = User::factory()->create();
  $user->delete();

  $this->assertModelMissing($user);
  ```
</CodeGroup>

### `expectsDatabaseQueryCount`

테스트 시작 부분에서 실행되는 데이터베이스 쿼리의 총 개수를 엄격하게 지정합니다. 실제 실행 횟수가 일치하지 않으면 실패합니다.

<CodeGroup>
  ```php Pest theme={null}
  $this->expectsDatabaseQueryCount(5);

  // Test...
  ```

  ```php PHPUnit theme={null}
  $this->expectsDatabaseQueryCount(5);

  // Test...
  ```
</CodeGroup>


## Related topics

- [데이터베이스 시딩](/ko/seeding.md)
- [데이터베이스 설정](/ko/database.md)
- [Laravel Scout](/ko/scout.md)
- [Orchestra Testbench로 Laravel 패키지를 테스트하기](/ko/advanced/package-testing.md)
- [데이터베이스 마이그레이션](/ko/migrations.md)
