HTTP 테스트
번역일: 2026년 6월 25일
HTTP 테스트
소개
Laravel은 애플리케이션에 HTTP 요청을 보내고 응답을 검사할 수 있는 직관적인 API를 제공합니다. 아래는 간단한 기능 테스트 예시입니다.
<?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);
}
}get 메서드는 애플리케이션에 GET 요청을 보내고, assertStatus 메서드는 반환된 응답의 HTTP 상태 코드를 검증합니다. Laravel은 이처럼 단순한 상태 코드 확인 외에도 응답 헤더, 본문 내용, JSON 구조 등을 검사하는 다양한 어설션을 제공합니다.
요청 만들기
테스트 내에서 get, post, put, patch, delete 메서드를 호출하면 애플리케이션에 요청을 보낼 수 있습니다. 이 메서드들은 실제 네트워크 요청을 발생시키지 않고, 내부적으로 요청을 시뮬레이션합니다.
이 메서드들은 Illuminate\Http\Response 인스턴스 대신 Illuminate\Testing\TestResponse 인스턴스를 반환하며, 이를 통해 다양한 어설션을 사용할 수 있습니다.
<?php
namespace Tests\Feature;
use Tests\TestCase;
class ExampleTest extends TestCase
{
/**
* 기본 요청 테스트 예시
*/
public function test_a_basic_request(): void
{
$response = $this->get('/');
$response->assertStatus(200);
}
}일반적으로 테스트 메서드 하나에서는 요청을 한 번만 보내는 것이 좋습니다. 하나의 테스트 메서드에서 여러 요청을 실행하면 예기치 않은 동작이 발생할 수 있습니다.
NOTE
테스트 실행 시 CSRF 미들웨어는 자동으로 비활성화됩니다.
요청 헤더 커스터마이징
withHeaders 메서드를 사용하면 요청을 보내기 전에 헤더를 원하는 대로 설정할 수 있습니다.
<?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' => '홍길동']);
$response->assertStatus(201);
}
}쿠키
요청 전에 쿠키를 설정하려면 withCookie 또는 withCookies 메서드를 사용합니다. withCookie는 쿠키 이름과 값을 인수로 받고, withCookies는 이름/값 쌍의 배열을 받습니다.
<?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' => '홍길동',
])->get('/');
}
}세션 / 인증
Laravel은 HTTP 테스트 중 세션을 다루기 위한 여러 헬퍼를 제공합니다. withSession 메서드를 사용하면 요청 전에 세션에 원하는 데이터를 미리 설정할 수 있습니다.
<?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('/');
}
}세션은 주로 인증된 사용자의 상태를 유지하는 데 사용됩니다. actingAs 헬퍼 메서드를 사용하면 특정 사용자를 현재 인증된 사용자로 간편하게 설정할 수 있습니다. 예를 들어 모델 팩토리로 사용자를 생성하고 인증할 수 있습니다.
<?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('/');
}
}actingAs 메서드의 두 번째 인수로 가드 이름을 전달하면 해당 가드로 인증합니다. 지정한 가드는 테스트가 진행되는 동안 기본 가드로 사용됩니다.
$this->actingAs($user, 'web')
응답 디버깅
요청을 보낸 후 응답 내용을 확인해야 할 때 dump, dumpHeaders, dumpSession 메서드를 사용할 수 있습니다.
<?php
namespace Tests\Feature;
use Tests\TestCase;
class ExampleTest extends TestCase
{
/**
* 응답 디버깅 예시
*/
public function test_basic_test(): void
{
$response = $this->get('/');
$response->dumpHeaders();
$response->dumpSession();
$response->dump();
}
}응답 내용을 출력한 뒤 실행을 즉시 중단하려면 dd, ddHeaders, ddSession 메서드를 사용합니다.
<?php
namespace Tests\Feature;
use Tests\TestCase;
class ExampleTest extends TestCase
{
/**
* dd를 활용한 응답 디버깅 예시
*/
public function test_basic_test(): void
{
$response = $this->get('/');
$response->ddHeaders();
$response->ddSession();
$response->dd();
}
}예외 처리
특정 예외가 발생하는지 테스트하고 싶을 때, Laravel의 예외 핸들러가 예외를 HTTP 응답으로 변환하지 않도록 withoutExceptionHandling 메서드를 요청 전에 호출합니다.
$response = $this->withoutExceptionHandling()->get('/');
PHP 언어나 사용 중인 라이브러리에서 더 이상 사용되지 않는(deprecated) 기능을 애플리케이션이 사용하고 있는지 확인하려면 withoutDeprecationHandling 메서드를 요청 전에 호출합니다. 이 메서드를 활성화하면 deprecation 경고가 예외로 변환되어 테스트가 실패합니다.
$response = $this->withoutDeprecationHandling()->get('/');
assertThrows 메서드를 사용하면 클로저 내에서 특정 타입의 예외가 발생하는지 확인할 수 있습니다.
$this->assertThrows(
fn () => (new ProcessOrder)->execute(),
OrderInvalid::class
);JSON API 테스트
Laravel은 JSON API 테스트를 위한 전용 헬퍼도 제공합니다. json, getJson, postJson, putJson, patchJson, deleteJson, optionsJson 메서드를 사용하면 각 HTTP 메서드로 JSON 요청을 손쉽게 보낼 수 있습니다. 아래는 /api/user에 POST 요청을 보내고 반환된 JSON 데이터를 검증하는 예시입니다.
<?php
namespace Tests\Feature;
use Tests\TestCase;
class ExampleTest extends TestCase
{
/**
* JSON API 요청 테스트 예시
*/
public function test_making_an_api_request(): void
{
$response = $this->postJson('/api/user', ['name' => '홍길동']);
$response
->assertStatus(201)
->assertJson([
'created' => true,
]);
}
}JSON 응답 데이터는 배열처럼 직접 접근할 수도 있습니다.
$this->assertTrue($response['created']);
NOTE
assertJson 메서드는 응답을 배열로 변환한 뒤 PHPUnit::assertArraySubset을 사용해 주어진 배열이 JSON 응답 내에 포함되어 있는지 확인합니다. 따라서 JSON 응답에 다른 프로퍼티가 있더라도, 지정한 데이터가 존재하면 테스트는 통과합니다.
정확한 JSON 일치 검증
assertJson은 부분 일치를 허용하지만, 반환된 JSON과 정확히 일치하는지 검증하려면 assertExactJson 메서드를 사용합니다.
<?php
namespace Tests\Feature;
use Tests\TestCase;
class ExampleTest extends TestCase
{
/**
* 정확한 JSON 일치 테스트 예시
*/
public function test_asserting_an_exact_json_match(): void
{
$response = $this->postJson('/user', ['name' => '홍길동']);
$response
->assertStatus(201)
->assertExactJson([
'created' => true,
]);
}
}JSON 경로 검증
특정 경로의 JSON 값을 검증하려면 assertJsonPath 메서드를 사용합니다.
<?php
namespace Tests\Feature;
use Tests\TestCase;
class ExampleTest extends TestCase
{
/**
* JSON 경로 값 검증 테스트 예시
*/
public function test_asserting_a_json_paths_value(): void
{
$response = $this->postJson('/user', ['name' => '홍길동']);
$response
->assertStatus(201)
->assertJsonPath('team.owner.name', 'Darian');
}
}assertJsonPath는 클로저도 인수로 받을 수 있어, 동적으로 검증 조건을 구성할 수 있습니다.
$response->assertJsonPath('team.owner.name', fn (string $name) => strlen($name) >= 3);
Fluent JSON 테스트
Laravel은 JSON 응답을 체이닝 방식으로 유연하게 검증하는 Fluent JSON 테스트 기능을 제공합니다. assertJson 메서드에 클로저를 전달하면 Illuminate\Testing\Fluent\AssertableJson 인스턴스를 통해 다양한 어설션을 체이닝할 수 있습니다. where는 특정 속성의 값을 검증하고, missing은 특정 속성이 존재하지 않음을 검증합니다.
use Illuminate\Testing\Fluent\AssertableJson;
/**
* Fluent JSON 테스트 예시
*/
public function test_fluent_json(): void
{
$response = $this->getJson('/users/1');
$response
->assertJson(fn (AssertableJson $json) =>
$json->where('id', 1)
->where('name', '홍길동')
->where('email', fn (string $email) => str($email)->is('hong@example.com'))
->whereNot('status', 'pending')
->missing('password')
->etc()
);
}etc 메서드의 역할
위 예시에서 체이닝 마지막에 etc 메서드를 호출했습니다. 이 메서드는 JSON 객체에 검증하지 않은 다른 속성이 있을 수 있음을 Laravel에 알려줍니다. etc를 사용하지 않으면, 명시적으로 검증하지 않은 속성이 JSON에 포함되어 있을 경우 테스트가 실패합니다.
이 동작은 의도치 않게 민감한 정보가 JSON 응답에 노출되는 것을 방지하기 위한 것입니다. 개발자가 모든 속성을 명시적으로 검증하거나, etc를 통해 추가 속성 허용 의사를 명확히 표시하도록 강제합니다.
단, etc를 사용하더라도 중첩된 배열 내부까지 추가 속성이 없다고 보장하지는 않습니다. etc는 해당 메서드가 호출된 중첩 수준에서만 추가 속성을 허용합니다.
속성 존재 여부 검증
속성이 존재하거나 존재하지 않음을 확인하려면 has와 missing 메서드를 사용합니다.
$response->assertJson(fn (AssertableJson $json) =>
$json->has('data')
->missing('message')
);여러 속성을 한 번에 검증하려면 hasAll과 missingAll을 사용합니다.
$response->assertJson(fn (AssertableJson $json) =>
$json->hasAll(['status', 'data'])
->missingAll(['message', 'code'])
);주어진 속성 목록 중 하나 이상이 존재하는지 확인하려면 hasAny를 사용합니다.
$response->assertJson(fn (AssertableJson $json) =>
$json->has('status')
->hasAny('data', 'message', 'code')
);JSON 컬렉션 검증
라우트가 여러 항목을 포함한 JSON 응답을 반환하는 경우가 많습니다. 예를 들어 사용자 목록을 반환하는 라우트가 있다면:
Route::get('/users', function () {
return User::all();
});이런 경우 Fluent JSON의 has 메서드로 항목 수를 검증하고, first 메서드로 첫 번째 항목에 대해 세부 검증을 수행할 수 있습니다.
$response
->assertJson(fn (AssertableJson $json) =>
$json->has(3)
->first(fn (AssertableJson $json) =>
$json->where('id', 1)
->where('name', '홍길동')
->where('email', fn (string $email) => str($email)->is('hong@example.com'))
->missing('password')
->etc()
)
);JSON 컬렉션 범위 지정 검증
라우트가 키 이름이 지정된 JSON 컬렉션을 반환하는 경우:
Route::get('/users', function () {
return [
'meta' => [...],
'users' => User::all(),
];
})has 메서드를 중첩해서 사용하면 컬렉션 항목 수와 각 항목의 세부 내용을 함께 검증할 수 있습니다.
$response
->assertJson(fn (AssertableJson $json) =>
$json->has('meta')
->has('users', 3)
->has('users.0', fn (AssertableJson $json) =>
$json->where('id', 1)
->where('name', '홍길동')
->where('email', fn (string $email) => str($email)->is('hong@example.com'))
->missing('password')
->etc()
)
);has 메서드의 세 번째 인수로 클로저를 전달하면, has 호출을 두 번 하지 않고 항목 수 검증과 첫 번째 항목 검증을 한 번에 처리할 수 있습니다.
$response
->assertJson(fn (AssertableJson $json) =>
$json->has('meta')
->has('users', 3, fn (AssertableJson $json) =>
$json->where('id', 1)
->where('name', '홍길동')
->where('email', fn (string $email) => str($email)->is('hong@example.com'))
->missing('password')
->etc()
)
);JSON 타입 검증
JSON 응답의 속성이 특정 타입인지 확인하려면 whereType과 whereAllType 메서드를 사용합니다.
$response->assertJson(fn (AssertableJson $json) =>
$json->whereType('id', 'integer')
->whereAllType([
'users.0.name' => 'string',
'meta' => 'array'
])
);| 문자를 사용하거나 배열로 여러 타입을 지정할 수 있습니다. 값이 지정된 타입 중 하나라도 일치하면 검증이 통과합니다.
$response->assertJson(fn (AssertableJson $json) =>
$json->whereType('name', 'string|null')
->whereType('id', ['string', 'integer'])
);whereType과 whereAllType이 인식하는 타입은 string, integer, double, boolean, array, null입니다.
파일 업로드 테스트
Illuminate\Http\UploadedFile 클래스의 fake 메서드를 사용하면 테스트용 더미 파일이나 이미지를 생성할 수 있습니다. Storage 파사드의 fake 메서드와 함께 사용하면 파일 업로드 테스트가 훨씬 간편해집니다. 아래는 프로필 이미지 업로드를 테스트하는 예시입니다.
<?php
namespace Tests\Feature;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
class ExampleTest 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());
}
}파일이 존재하지 않음을 검증하려면 assertMissing 메서드를 사용합니다.
Storage::fake('avatars');
// ...
Storage::disk('avatars')->assertMissing('missing.jpg');가짜 파일 커스터마이징
fake 메서드로 이미지를 생성할 때 가로, 세로, 파일 크기(킬로바이트)를 지정하여 유효성 검사 규칙을 더 정확하게 테스트할 수 있습니다.
UploadedFile::fake()->image('avatar.jpg', $width, $height)->size(100);
이미지 외의 다른 파일 형식은 create 메서드로 생성합니다.
UploadedFile::fake()->create('document.pdf', $sizeInKilobytes);
MIME 타입을 명시적으로 지정해야 하는 경우 세 번째 인수를 전달합니다.
UploadedFile::fake()->create(
'document.pdf', $sizeInKilobytes, 'application/pdf'
);뷰 테스트
HTTP 요청을 시뮬레이션하지 않고 뷰만 단독으로 렌더링해서 테스트할 수 있습니다. 테스트 내에서 view 메서드를 호출하면 되며, 뷰 이름과 선택적 데이터 배열을 인수로 받습니다. 이 메서드는 Illuminate\Testing\TestView 인스턴스를 반환하며, 뷰 내용에 대한 다양한 어설션을 제공합니다.
<?php
namespace Tests\Feature;
use Tests\TestCase;
class ExampleTest extends TestCase
{
public function test_a_welcome_view_can_be_rendered(): void
{
$view = $this->view('welcome', ['name' => '홍길동']);
$view->assertSee('홍길동');
}
}TestView는 assertSee, assertSeeInOrder, assertSeeText, assertSeeTextInOrder, assertDontSee, assertDontSeeText 어설션 메서드를 제공합니다.
렌더링된 뷰의 원본 문자열이 필요하다면 TestView 인스턴스를 문자열로 캐스팅합니다.
$contents = (string) $this->view('welcome');
에러 공유
일부 뷰는 Laravel이 제공하는 전역 에러 백에 의존합니다. withViewErrors 메서드를 사용하면 에러 백에 오류 메시지를 미리 주입할 수 있습니다.
$view = $this->withViewErrors([
'name' => ['올바른 이름을 입력해주세요.']
])->view('form');
$view->assertSee('올바른 이름을 입력해주세요.');Blade 및 컴포넌트 렌더링
blade 메서드를 사용하면 Blade 문자열을 직접 평가하고 렌더링할 수 있습니다. view 메서드와 마찬가지로 Illuminate\Testing\TestView 인스턴스를 반환합니다.
$view = $this->blade(
'<x-component :name="$name" />',
['name' => '홍길동']
);
$view->assertSee('홍길동');Blade 컴포넌트를 평가하고 렌더링하려면 component 메서드를 사용합니다. 이 메서드는 Illuminate\Testing\TestComponent 인스턴스를 반환합니다.
$view = $this->component(Profile::class, ['name' => '홍길동']);
$view->assertSee('홍길동');사용 가능한 어설션
응답 어설션
Illuminate\Testing\TestResponse 클래스는 테스트에서 활용할 수 있는 다양한 어설션 메서드를 제공합니다. 이 어설션들은 json, get, post, put, delete 등의 테스트 메서드가 반환하는 응답 객체에서 사용합니다.
assertAccepted assertBadRequest assertConflict assertCookie assertCookieExpired assertCookieNotExpired assertCookieMissing assertCreated assertDontSee assertDontSeeText assertDownload assertExactJson assertForbidden assertFound assertGone assertHeader assertHeaderMissing assertInternalServerError assertJson assertJsonCount assertJsonFragment assertJsonIsArray assertJsonIsObject assertJsonMissing assertJsonMissingExact assertJsonMissingValidationErrors assertJsonPath assertJsonMissingPath assertJsonStructure assertJsonValidationErrors assertJsonValidationErrorFor assertLocation assertMethodNotAllowed assertMovedPermanently assertContent assertNoContent assertStreamedContent assertNotFound assertOk [assertPaymentRequired](#assert