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

# HTTP 테스트

> Laravel의 HTTP 테스트 기능을 사용한 요청의 시뮬레이션, 어서션, 인증 테스트, 파일 업로드 테스트의 설명

## 시작하기

Laravel은 HTTP 요청을 시뮬레이트해 응답을 검증하기 위한 풍부한 API를 제공하고 있습니다.
실제 HTTP 서버를 세우지 않고 애플리케이션에의 요청을 테스트 내에서 재현할 수 있습니다.

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

  test('애플리케이션이 정상적인 응답을 반환한다', function () {
      $response = $this->get('/');

      $response->assertStatus(200);
  });
  ```

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

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_the_application_returns_a_successful_response(): void
      {
          $response = $this->get('/');

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

`get()` 메서드는 애플리케이션에 `GET` 요청을 보내고, `assertStatus()`는 반환된 응답의 HTTP 스테이터스 코드를 검증합니다.

<Info>
  테스트 실행 중에는 CSRF 미들웨어가 자동으로 무효화됩니다. 테스트에서 명시적으로 무효화할 필요는 없습니다.
</Info>

## 요청의 작성

테스트 내에서는 `get`, `post`, `put`, `patch`, `delete` 메서드를 사용해 요청을 보낼 수 있습니다.
이 메서드들은 네트워크 요청을 실제로는 발행하지 않고, 애플리케이션 내부에서 시뮬레이트합니다.
반환값은 `Illuminate\Testing\TestResponse`의 인스턴스이며, 다양한 어서션 메서드를 제공합니다.

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

  test('기본적인 요청', function () {
      $response = $this->get('/');

      $response->assertStatus(200);
  });
  ```

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

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_a_basic_request(): void
      {
          $response = $this->get('/');

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

<Warning>
  하나의 테스트 메서드 내에서는 기본적으로 하나의 요청만 보내는 것을 권장합니다. 여러 요청을 동일 테스트 내에서 실행하면 예기치 못한 동작이 발생할 수 있습니다.
</Warning>

### 요청 헤더의 커스터마이즈

`withHeaders()` 메서드를 사용해 요청의 헤더를 커스터마이즈할 수 있습니다.

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

  test('헤더 포함 요청', function () {
      $response = $this->withHeaders([
          'X-Header' => 'Value',
      ])->post('/user', ['name' => 'Sally']);

      $response->assertStatus(201);
  });
  ```

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

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_interacting_with_headers(): void
      {
          $response = $this->withHeaders([
              'X-Header' => 'Value',
          ])->post('/user', ['name' => 'Sally']);

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

### 쿠키

`withCookie()` 또는 `withCookies()` 메서드로 요청 전에 쿠키 값을 설정할 수 있습니다.

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

  test('쿠키 포함 요청', function () {
      $response = $this->withCookie('color', 'blue')->get('/');

      $response = $this->withCookies([
          'color' => 'blue',
          'name'  => 'Taylor',
      ])->get('/');
  });
  ```

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

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_interacting_with_cookies(): void
      {
          $response = $this->withCookie('color', 'blue')->get('/');

          $response = $this->withCookies([
              'color' => 'blue',
              'name'  => 'Taylor',
          ])->get('/');
      }
  }
  ```
</CodeGroup>

### 세션과 인증

`withSession()` 메서드를 사용해 요청 전에 세션 데이터를 설정할 수 있습니다.

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

  test('세션 포함 요청', function () {
      $response = $this->withSession(['banned' => false])->get('/');
  });
  ```

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

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_interacting_with_the_session(): void
      {
          $response = $this->withSession(['banned' => false])->get('/');
      }
  }
  ```
</CodeGroup>

`actingAs()` 메서드로 인증 사용자로서 요청을 보낼 수 있습니다. 모델 팩토리와 조합해서 사용합니다.

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

  use App\Models\User;

  test('인증이 필요한 액션', function () {
      $user = User::factory()->create();

      $response = $this->actingAs($user)
          ->withSession(['banned' => false])
          ->get('/');
  });
  ```

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

  namespace Tests\Feature;

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

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

          $response = $this->actingAs($user)
              ->withSession(['banned' => false])
              ->get('/');
      }
  }
  ```
</CodeGroup>

`actingAs()`의 두 번째 인수에 가드 이름을 전달하면 그 가드로 인증됩니다. 테스트 중에는 그 가드가 기본이 됩니다.

```php theme={null}
$this->actingAs($user, 'web');
```

미인증 상태로 요청하고 싶은 경우 `actingAsGuest()`를 사용합니다.

```php theme={null}
$this->actingAsGuest();
```

### 응답의 디버그

테스트 중에 응답의 내용을 확인하고 싶은 경우 `dump`, `dumpHeaders`, `dumpSession` 메서드를 사용합니다.

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

  test('응답의 디버그', function () {
      $response = $this->get('/');

      $response->dump();
      $response->dumpHeaders();
      $response->dumpSession();
  });
  ```

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

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_debug_response(): void
      {
          $response = $this->get('/');

          $response->dump();
          $response->dumpHeaders();
          $response->dumpSession();
      }
  }
  ```
</CodeGroup>

실행을 정지하고 싶은 경우 `dd`, `ddHeaders`, `ddBody`, `ddJson`, `ddSession` 메서드를 사용합니다.

```php theme={null}
$response->dd();
$response->ddHeaders();
$response->ddBody();
$response->ddJson();
$response->ddSession();
```

### 예외의 테스트

특정 예외가 스로우됨을 테스트하려면 `Exceptions` 파사드를 사용합니다.

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

  use App\Exceptions\InvalidOrderException;
  use Illuminate\Support\Facades\Exceptions;

  test('예외가 스로우된다', function () {
      Exceptions::fake();

      $response = $this->get('/order/1');

      // 예외가 스로우되었음을 확인
      Exceptions::assertReported(InvalidOrderException::class);

      // 예외의 내용을 확인
      Exceptions::assertReported(function (InvalidOrderException $e) {
          return $e->getMessage() === 'The order was invalid.';
      });
  });
  ```

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

  namespace Tests\Feature;

  use App\Exceptions\InvalidOrderException;
  use Illuminate\Support\Facades\Exceptions;
  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_exception_is_thrown(): void
      {
          Exceptions::fake();

          $response = $this->get('/');

          Exceptions::assertReported(InvalidOrderException::class);

          Exceptions::assertReported(function (InvalidOrderException $e) {
              return $e->getMessage() === 'The order was invalid.';
          });
      }
  }
  ```
</CodeGroup>

예외가 스로우되지 않았음을 확인하려면 `assertNotReported`나 `assertNothingReported`를 사용합니다.

```php theme={null}
Exceptions::assertNotReported(InvalidOrderException::class);

Exceptions::assertNothingReported();
```

예외 핸들링을 무효화해 요청을 보내려면 `withoutExceptionHandling()`을 사용합니다.

```php theme={null}
$response = $this->withoutExceptionHandling()->get('/');
```

클로저 내의 코드가 예외를 스로우하는지 테스트하려면 `assertThrows()`를 사용합니다.

```php theme={null}
$this->assertThrows(
    fn () => (new ProcessOrder)->execute(),
    OrderInvalid::class
);

// 예외의 내용을 확인하는 경우
$this->assertThrows(
    fn () => (new ProcessOrder)->execute(),
    fn (OrderInvalid $e) => $e->orderId() === 123
);
```

예외가 스로우되지 않음을 확인하려면 `assertDoesntThrow()`를 사용합니다.

```php theme={null}
$this->assertDoesntThrow(fn () => (new ProcessOrder)->execute());
```

## JSON API 의 테스트

Laravel은 JSON API의 테스트를 위한 헬퍼를 다수 제공하고 있습니다.
`json`, `getJson`, `postJson`, `putJson`, `patchJson`, `deleteJson`, `optionsJson` 메서드를 사용해 JSON 요청을 보낼 수 있습니다.

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

  test('API 요청 전송', function () {
      $response = $this->postJson('/api/user', ['name' => 'Sally']);

      $response
          ->assertStatus(201)
          ->assertJson([
              'created' => true,
          ]);
  });
  ```

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

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_making_an_api_request(): void
      {
          $response = $this->postJson('/api/user', ['name' => 'Sally']);

          $response
              ->assertStatus(201)
              ->assertJson([
                  'created' => true,
              ]);
      }
  }
  ```
</CodeGroup>

JSON 응답의 데이터에는 배열 변수로 접근할 수 있습니다.

<CodeGroup>
  ```php Pest theme={null}
  expect($response['created'])->toBeTrue();
  ```

  ```php PHPUnit theme={null}
  $this->assertTrue($response['created']);
  ```
</CodeGroup>

<Info>
  `assertJson()`은 응답을 배열로 변환해, 지정한 배열이 JSON 응답 안에 포함되어 있는지를 검증합니다. JSON에 다른 프로퍼티가 존재해도, 지정한 프래그먼트가 포함되어 있으면 테스트는 통과합니다.
</Info>

### 완전 일치의 어서션

`assertExactJson()`을 사용하면 반환된 JSON과 지정한 배열이 **완전히 일치**함을 검증할 수 있습니다.

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

  test('완전 일치의 JSON 어서션', function () {
      $response = $this->postJson('/user', ['name' => 'Sally']);

      $response
          ->assertStatus(201)
          ->assertExactJson([
              'created' => true,
          ]);
  });
  ```

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

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_asserting_an_exact_json_match(): void
      {
          $response = $this->postJson('/user', ['name' => 'Sally']);

          $response
              ->assertStatus(201)
              ->assertExactJson([
                  'created' => true,
              ]);
      }
  }
  ```
</CodeGroup>

### JSON 경로의 어서션

`assertJsonPath()`를 사용해 지정한 경로에 있는 데이터를 검증할 수 있습니다.

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

  test('JSON 경로의 어서션', function () {
      $response = $this->postJson('/user', ['name' => 'Sally']);

      $response
          ->assertStatus(201)
          ->assertJsonPath('team.owner.name', 'Darian');
  });
  ```

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

  namespace Tests\Feature;

  use Tests\TestCase;

  class ExampleTest extends TestCase
  {
      public function test_asserting_a_json_paths_value(): void
      {
          $response = $this->postJson('/user', ['name' => 'Sally']);

          $response
              ->assertStatus(201)
              ->assertJsonPath('team.owner.name', 'Darian');
      }
  }
  ```
</CodeGroup>

클로저를 전달해 더 유연하게 검증할 수도 있습니다.

```php theme={null}
$response->assertJsonPath('team.owner.name', fn (string $name) => strlen($name) >= 3);
```

### 플루언트한 JSON 테스트

`assertJson()`에 클로저를 전달하면 `AssertableJson` 인스턴스를 사용해 플루언트하게 어서션을 기술할 수 있습니다.

<CodeGroup>
  ```php Pest theme={null}
  use Illuminate\Testing\Fluent\AssertableJson;

  test('플루언트한 JSON 테스트', function () {
      $response = $this->getJson('/users/1');

      $response
          ->assertJson(fn (AssertableJson $json) =>
              $json->where('id', 1)
                  ->where('name', 'Victoria Faith')
                  ->where('email', fn (string $email) => str($email)->is('victoria@gmail.com'))
                  ->whereNot('status', 'pending')
                  ->missing('password')
                  ->etc()
          );
  });
  ```

  ```php PHPUnit theme={null}
  use Illuminate\Testing\Fluent\AssertableJson;

  public function test_fluent_json(): void
  {
      $response = $this->getJson('/users/1');

      $response
          ->assertJson(fn (AssertableJson $json) =>
              $json->where('id', 1)
                  ->where('name', 'Victoria Faith')
                  ->where('email', fn (string $email) => str($email)->is('victoria@gmail.com'))
                  ->whereNot('status', 'pending')
                  ->missing('password')
                  ->etc()
          );
  }
  ```
</CodeGroup>

<Tip>
  `etc()` 메서드는 어서션 대상 이외의 프로퍼티가 존재함을 허가합니다. `etc()`를 사용하지 않는 경우, 어서션하지 않은 프로퍼티가 존재하면 테스트가 실패합니다. 이에 따라 의도치 않게 기밀 정보를 응답에 포함시켜 버리는 것을 방지합니다.
</Tip>

속성의 존재·부재를 확인하려면 `has()`와 `missing()`을 사용합니다.

```php theme={null}
$response->assertJson(fn (AssertableJson $json) =>
    $json->has('data')
        ->missing('message')
);
```

여러 속성을 함께 확인하려면 `hasAll()`이나 `missingAll()`을 사용합니다.

```php theme={null}
$response->assertJson(fn (AssertableJson $json) =>
    $json->hasAll(['status', 'data'])
        ->missingAll(['message', 'code'])
);
```

#### JSON 컬렉션의 어서션

라우트가 여러 아이템을 포함한 JSON 응답을 반환하는 경우, `has()` 메서드로 아이템 수나 컬렉션의 내용을 검증할 수 있습니다.

```php theme={null}
$response
    ->assertJson(fn (AssertableJson $json) =>
        $json->has(3)
            ->first(fn (AssertableJson $json) =>
                $json->where('id', 1)
                    ->where('name', 'Victoria Faith')
                    ->missing('password')
                    ->etc()
            )
    );
```

모든 아이템에 같은 어서션을 적용하려면 `each()`를 사용합니다.

```php theme={null}
$response
    ->assertJson(fn (AssertableJson $json) =>
        $json->has(3)
            ->each(fn (AssertableJson $json) =>
                $json->whereType('id', 'integer')
                    ->whereType('name', 'string')
                    ->whereType('email', 'string')
                    ->missing('password')
                    ->etc()
            )
    );
```

#### JSON 의 타입 어서션

`whereType()`이나 `whereAllType()`을 사용해 프로퍼티의 타입을 검증할 수 있습니다.

```php theme={null}
$response->assertJson(fn (AssertableJson $json) =>
    $json->whereType('id', 'integer')
        ->whereAllType([
            'users.0.name' => 'string',
            'meta' => 'array'
        ])
);
```

`|` 문자로 여러 타입을 지정할 수도 있습니다. 어느 타입에라도 일치하면 어서션은 통과합니다.

```php theme={null}
$response->assertJson(fn (AssertableJson $json) =>
    $json->whereType('name', 'string|null')
        ->whereType('id', ['string', 'integer'])
);
```

이용 가능한 타입은 `string`, `integer`, `double`, `boolean`, `array`, `null`입니다.

## 인증 테스트

`actingAs()`를 사용해 인증된 사용자로서 요청을 보낼 수 있습니다.

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

  use App\Models\User;
  use Illuminate\Foundation\Testing\RefreshDatabase;

  uses(RefreshDatabase::class);

  test('인증된 사용자가 대시보드를 표시할 수 있다', function () {
      $user = User::factory()->create();

      $response = $this->actingAs($user)->get('/dashboard');

      $response->assertStatus(200);
  });

  test('미인증 사용자는 리다이렉트된다', function () {
      $response = $this->get('/dashboard');

      $response->assertRedirect('/login');
  });
  ```

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

  namespace Tests\Feature;

  use App\Models\User;
  use Illuminate\Foundation\Testing\RefreshDatabase;
  use Tests\TestCase;

  class DashboardTest extends TestCase
  {
      use RefreshDatabase;

      public function test_authenticated_users_can_view_the_dashboard(): void
      {
          $user = User::factory()->create();

          $response = $this->actingAs($user)->get('/dashboard');

          $response->assertStatus(200);
      }

      public function test_unauthenticated_users_are_redirected(): void
      {
          $response = $this->get('/dashboard');

          $response->assertRedirect('/login');
      }
  }
  ```
</CodeGroup>

특정 가드로 인증하려면 두 번째 인수에 가드 이름을 지정합니다.

```php theme={null}
$this->actingAs($user, 'api');
```

### 사용자 등록 플로우의 테스트 예시

실제 사용자 등록 엔드포인트를 테스트하는 예시입니다.

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

  use App\Models\User;
  use Illuminate\Foundation\Testing\RefreshDatabase;

  uses(RefreshDatabase::class);

  test('사용자가 등록할 수 있다', function () {
      $response = $this->post('/register', [
          'name'                  => 'Test User',
          'email'                 => 'test@example.com',
          'password'              => 'password',
          'password_confirmation' => 'password',
      ]);

      $response->assertRedirect('/dashboard');
      $this->assertDatabaseHas('users', ['email' => 'test@example.com']);
  });

  test('중복된 이메일 주소로는 등록할 수 없다', function () {
      User::factory()->create(['email' => 'test@example.com']);

      $response = $this->post('/register', [
          'name'                  => 'Test User',
          'email'                 => 'test@example.com',
          'password'              => 'password',
          'password_confirmation' => 'password',
      ]);

      $response->assertSessionHasErrors('email');
  });
  ```

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

  namespace Tests\Feature;

  use App\Models\User;
  use Illuminate\Foundation\Testing\RefreshDatabase;
  use Tests\TestCase;

  class RegistrationTest extends TestCase
  {
      use RefreshDatabase;

      public function test_user_can_register(): void
      {
          $response = $this->post('/register', [
              'name'                  => 'Test User',
              'email'                 => 'test@example.com',
              'password'              => 'password',
              'password_confirmation' => 'password',
          ]);

          $response->assertRedirect('/dashboard');
          $this->assertDatabaseHas('users', ['email' => 'test@example.com']);
      }

      public function test_duplicate_email_cannot_register(): void
      {
          User::factory()->create(['email' => 'test@example.com']);

          $response = $this->post('/register', [
              'name'                  => 'Test User',
              'email'                 => 'test@example.com',
              'password'              => 'password',
              'password_confirmation' => 'password',
          ]);

          $response->assertSessionHasErrors('email');
      }
  }
  ```
</CodeGroup>

## 세션의 테스트

`withSession()`으로 세션 데이터를 사전에 세팅해 요청을 보낼 수 있습니다.
`assertSessionHas()`로 세션에 값이 존재하는지를 검증할 수 있습니다.

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

  test('세션의 값을 검증한다', function () {
      $response = $this->withSession(['locale' => 'ja'])->get('/');

      $response->assertSessionHas('locale', 'ja');
  });
  ```

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

  namespace Tests\Feature;

  use Tests\TestCase;

  class SessionTest extends TestCase
  {
      public function test_session_value(): void
      {
          $response = $this->withSession(['locale' => 'ja'])->get('/');

          $response->assertSessionHas('locale', 'ja');
      }
  }
  ```
</CodeGroup>

### 세션 어서션 목록

| 메서드                                     | 설명                    |
| --------------------------------------- | --------------------- |
| `assertSessionHas($key, $value)`        | 세션에 지정한 키와 값이 존재      |
| `assertSessionHasAll([...])`            | 세션에 여러 키와 값이 존재       |
| `assertSessionHasErrors($keys)`         | 세션에 밸리데이션 에러가 존재      |
| `assertSessionHasErrorsIn($bag, $keys)` | 지정한 에러 백에 에러가 존재      |
| `assertSessionHasNoErrors()`            | 세션에 밸리데이션 에러가 존재하지 않음 |
| `assertSessionDoesntHaveErrors()`       | 세션에 밸리데이션 에러가 존재하지 않음 |
| `assertSessionMissing($key)`            | 세션에 지정한 키가 존재하지 않음    |

## 파일 업로드의 테스트

`Illuminate\Http\UploadedFile` 클래스의 `fake()` 메서드를 사용해 더미 파일이나 이미지를 생성할 수 있습니다.
`Storage` 파사드의 `fake()` 메서드와 조합함으로써 파일 업로드를 간단히 테스트할 수 있습니다.

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

  use Illuminate\Http\UploadedFile;
  use Illuminate\Support\Facades\Storage;

  test('아바타 이미지를 업로드할 수 있다', function () {
      Storage::fake('avatars');

      $file = UploadedFile::fake()->image('avatar.jpg');

      $response = $this->post('/avatar', [
          'avatar' => $file,
      ]);

      Storage::disk('avatars')->assertExists($file->hashName());
  });
  ```

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

  namespace Tests\Feature;

  use Illuminate\Http\UploadedFile;
  use Illuminate\Support\Facades\Storage;
  use Tests\TestCase;

  class AvatarTest extends TestCase
  {
      public function test_avatars_can_be_uploaded(): void
      {
          Storage::fake('avatars');

          $file = UploadedFile::fake()->image('avatar.jpg');

          $response = $this->post('/avatar', [
              'avatar' => $file,
          ]);

          Storage::disk('avatars')->assertExists($file->hashName());
      }
  }
  ```
</CodeGroup>

파일이 존재하지 않음을 확인하려면 `assertMissing()`을 사용합니다.

```php theme={null}
Storage::disk('avatars')->assertMissing('missing.jpg');
```

### 더미 파일의 커스터마이즈

이미지의 크기나 파일 크기를 지정할 수 있습니다. 밸리데이션 룰의 테스트에 편리합니다.

```php theme={null}
// 폭·높이·파일 크기를 지정(크기는 KB 단위)
UploadedFile::fake()->image('avatar.jpg', $width, $height)->size(100);

// 임의의 파일 타입을 작성
UploadedFile::fake()->create('document.pdf', $sizeInKilobytes);

// MIME 타입을 명시적으로 지정
UploadedFile::fake()->create(
    'document.pdf', $sizeInKilobytes, 'application/pdf'
);
```

## 뷰의 테스트

HTTP 요청을 시뮬레이트하지 않고 뷰를 직접 렌더링해 테스트할 수 있습니다.
`view()` 메서드는 뷰 이름과 옵션으로 데이터의 배열을 받아 `Illuminate\Testing\TestView`의 인스턴스를 반환합니다.

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

  test('웰컴 뷰가 렌더링된다', function () {
      $view = $this->view('welcome', ['name' => 'Taylor']);

      $view->assertSee('Taylor');
  });
  ```

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

  namespace Tests\Feature;

  use Tests\TestCase;

  class ViewTest extends TestCase
  {
      public function test_a_welcome_view_can_be_rendered(): void
      {
          $view = $this->view('welcome', ['name' => 'Taylor']);

          $view->assertSee('Taylor');
      }
  }
  ```
</CodeGroup>

`TestView` 클래스에서는 다음의 어서션 메서드를 사용할 수 있습니다.

| 메서드                           | 설명                        |
| ----------------------------- | ------------------------- |
| `assertSee($value)`           | 뷰에 지정한 문자열이 포함됨           |
| `assertSeeInOrder([...])`     | 뷰에 지정한 문자열이 순서대로 포함됨      |
| `assertSeeText($value)`       | 뷰의 텍스트에 지정한 문자열이 포함됨      |
| `assertSeeTextInOrder([...])` | 뷰의 텍스트에 지정한 문자열이 순서대로 포함됨 |
| `assertDontSee($value)`       | 뷰에 지정한 문자열이 포함되지 않음       |
| `assertDontSeeText($value)`   | 뷰의 텍스트에 지정한 문자열이 포함되지 않음  |

렌더링된 뷰의 내용을 문자열로 취득하려면 `TestView` 인스턴스를 문자열로 캐스트합니다.

```php theme={null}
$contents = (string) $this->view('welcome');
```

밸리데이션 에러를 뷰에 전달하려면 `withViewErrors()`를 사용합니다.

```php theme={null}
$view = $this->withViewErrors([
    'name' => ['유효한 이름을 입력해 주십시오.']
])->view('form');

$view->assertSee('유효한 이름을 입력해 주십시오.');
```

### 컴포넌트의 테스트

`blade()` 메서드를 사용해 원시 Blade 템플릿 문자열을 렌더링할 수 있습니다.

```php theme={null}
$view = $this->blade(
    '<x-component :name="$name" />',
    ['name' => 'Taylor']
);

$view->assertSee('Taylor');
```

`component()` 메서드를 사용해 Blade 컴포넌트를 렌더링할 수 있습니다. `Illuminate\Testing\TestComponent`의 인스턴스를 반환합니다.

```php theme={null}
$view = $this->component(Profile::class, ['name' => 'Taylor']);

$view->assertSee('Taylor');
```

## 응답 어서션 목록

`Illuminate\Testing\TestResponse` 클래스가 제공하는 주요 어서션 메서드입니다.

### HTTP 스테이터스

| 메서드                              | 설명                        |
| -------------------------------- | ------------------------- |
| `assertOk()`                     | 200 OK                    |
| `assertCreated()`                | 201 Created               |
| `assertAccepted()`               | 202 Accepted              |
| `assertNoContent($status = 204)` | 204 No Content            |
| `assertBadRequest()`             | 400 Bad Request           |
| `assertUnauthorized()`           | 401 Unauthorized          |
| `assertForbidden()`              | 403 Forbidden             |
| `assertNotFound()`               | 404 Not Found             |
| `assertUnprocessable()`          | 422 Unprocessable Entity  |
| `assertTooManyRequests()`        | 429 Too Many Requests     |
| `assertInternalServerError()`    | 500 Internal Server Error |
| `assertStatus($code)`            | 지정한 스테이터스 코드              |
| `assertSuccessful()`             | 2xx 계열의 스테이터스 코드          |
| `assertClientError()`            | 4xx 계열의 스테이터스 코드          |
| `assertServerError()`            | 5xx 계열의 스테이터스 코드          |

### 리다이렉트

| 메서드                                           | 설명                      |
| --------------------------------------------- | ----------------------- |
| `assertRedirect($uri)`                        | 지정한 URI 로 리다이렉트         |
| `assertRedirectContains($string)`             | 리다이렉트 URI 에 지정한 문자열이 포함 |
| `assertRedirectToRoute($name, $params)`       | 지정한 라우트로 리다이렉트          |
| `assertRedirectToSignedRoute($name, $params)` | 지정한 서명 부착 라우트로 리다이렉트    |
| `assertRedirectBack()`                        | 직전의 URL 로 리다이렉트         |

### 콘텐츠

| 메서드                                  | 설명               |
| ------------------------------------ | ---------------- |
| `assertSee($value, $escaped = true)` | 지정한 값이 응답에 포함    |
| `assertSeeInOrder(array $values)`    | 지정한 값이 순서대로 포함   |
| `assertSeeText($value)`              | 지정한 텍스트가 포함      |
| `assertDontSee($value)`              | 지정한 값이 포함되지 않음   |
| `assertDontSeeText($value)`          | 지정한 텍스트가 포함되지 않음 |
| `assertContent($value)`              | 응답 바디가 지정한 값과 일치 |
| `assertDownload($filename)`          | 다운로드 응답임         |

### JSON

| 메서드                                        | 설명                         |
| ------------------------------------------ | -------------------------- |
| `assertJson(array $data)`                  | JSON 응답이 지정한 데이터를 포함       |
| `assertExactJson(array $data)`             | JSON 응답이 지정한 데이터에 완전 일치    |
| `assertJsonPath($path, $value)`            | 지정한 경로의 값이 일치              |
| `assertJsonMissingPath($path)`             | 지정한 경로가 존재하지 않음            |
| `assertJsonStructure(array $structure)`    | JSON 이 지정한 구조를 가짐          |
| `assertJsonCount($count, $key)`            | 지정한 키의 JSON 이 지정 수의 요소를 가짐 |
| `assertJsonFragment(array $data)`          | JSON 에 지정한 프래그먼트가 포함       |
| `assertJsonMissing(array $data)`           | JSON 에 지정한 데이터가 포함되지 않음    |
| `assertJsonIsArray()`                      | JSON 이 어레이임                |
| `assertJsonIsObject()`                     | JSON 이 객체임                 |
| `assertJsonValidationErrors($keys)`        | 지정한 키의 밸리데이션 에러가 포함        |
| `assertJsonMissingValidationErrors($keys)` | 지정한 키의 밸리데이션 에러가 포함되지 않음   |

### 헤더와 쿠키

| 메서드                                 | 설명                  |
| ----------------------------------- | ------------------- |
| `assertHeader($headerName, $value)` | 지정한 헤더가 존재          |
| `assertHeaderMissing($headerName)`  | 지정한 헤더가 존재하지 않음     |
| `assertCookie($name, $value)`       | 지정한 쿠키가 존재          |
| `assertCookieExpired($name)`        | 지정한 쿠키가 기한 만료       |
| `assertCookieMissing($name)`        | 지정한 쿠키가 존재하지 않음     |
| `assertPlainCookie($name, $value)`  | 지정한 암호화되지 않은 쿠키가 존재 |

### 뷰

| 메서드                             | 설명                  |
| ------------------------------- | ------------------- |
| `assertViewIs($value)`          | 지정한 뷰가 반환됨          |
| `assertViewHas($key, $value)`   | 뷰에 지정한 데이터가 존재      |
| `assertViewHasAll(array $data)` | 뷰에 여러 데이터가 존재       |
| `assertViewMissing($key)`       | 뷰에 지정한 데이터가 존재하지 않음 |

### 밸리데이션

| 메서드                    | 설명                  |
| ---------------------- | ------------------- |
| `assertValid($keys)`   | 지정한 키에 밸리데이션 에러가 없음 |
| `assertInvalid($keys)` | 지정한 키에 밸리데이션 에러가 있음 |

## TDD 를 실천하기 위한 포인트

<Tip>
  HTTP 테스트는 TDD(테스트 주도 개발)와 궁합이 발군입니다. 다음의 포인트를 의식하면 더 효과적입니다.
</Tip>

<AccordionGroup>
  <Accordion title="Feature 테스트에서 시작">
    HTTP 테스트는 `tests/Feature/` 디렉터리에 작성합니다. 애플리케이션 밖에서 본 동작(요청→응답)을 최초에 정의함으로써 구현해야 할 기능이 명확해집니다.
  </Accordion>

  <Accordion title="RefreshDatabase 를 사용">
    데이터베이스를 사용하는 테스트에서는 `RefreshDatabase` 트레이트를 사용합시다. 각 테스트 후에 데이터베이스가 리셋되어, 테스트 간의 데이터 간섭을 방지할 수 있습니다. 테스트의 독립성을 유지함으로써 실행 순서에 의존하지 않는 안정된 테스트 스위트를 구축할 수 있습니다.
  </Accordion>

  <Accordion title="팩토리를 적극적으로 사용">
    `User::factory()->create()`와 같은 모델 팩토리를 사용하면 테스트 데이터의 작성이 간단해집니다. 특정 상태를 가진 모델을 작성하기 위해 팩토리의 상태(state)를 정의해 두면 테스트의 가독성이 향상됩니다.
  </Accordion>

  <Accordion title="1테스트 1어서션">
    하나의 테스트 메서드에서는 가급적 하나의 것을 검증합시다. 테스트가 실패했을 때 원인을 특정하기 쉬워집니다. "Arrange(준비) → Act(실행) → Assert(검증)"의 AAA 패턴을 의식하면 테스트가 읽기 쉬워집니다.
  </Accordion>

  <Accordion title="인증 테스트를 잊지 않음">
    인증이 필요한 라우트에는 반드시 "인증 완료의 경우"와 "미인증의 경우" 양쪽의 테스트를 작성합시다. 보안 상의 문제를 조기에 발견할 수 있습니다.
  </Accordion>
</AccordionGroup>

## 관련 페이지

<Card title="테스트 입문" icon="flask" href="/ko/testing">
  Laravel에서의 테스트의 기본적인 작성법과 `php artisan test`의 사용법을 확인합니다.
</Card>


## Related topics

- [테스트 입문](/ko/testing.md)
- [테스트](/ko/packages/laravel-bluesky/testing.md)
- [Pest를 이용한 고급 테스트](/ko/advanced/testing-pest.md)
- [콘솔 테스트](/ko/console-tests.md)
- [Pest PHP로 시작하는 Laravel 테스트](/ko/blog/pest-introduction.md)
