Skip to content

제2.8장: API 테스트

학습 시간: 1시간


1. 왜 테스트가 필요한가요?

우주선을 만들었다고 상상해 보세요. 화성으로 보내기 전에 지구에서 수천 번의 검사를 수행합니다. 프로그래밍에서의 테스트도 마찬가지입니다. 테스트는:

  • 자신감을 줍니다: 코드를 변경할 수 있으며, 테스트가 통과하면 아무것도 손상시키지 않았다는 의미입니다.
  • 시간을 절약합니다: 변경할 때마다 Postman에서 모든 것을 수동으로 "클릭"하는 대신, 단일 명령을 실행하면 몇 초 만에 모든 것을 검사합니다.
  • 문서 역할을 합니다: 좋은 테스트는 API가 어떻게 작동해야 하는지 보여줍니다.

2. 테스트 "실험실" 설정

Laravel은 테스트 설정을 놀라울 정도로 간단하게 만듭니다. 기본적으로 주 데이터베이스에 영향을 주지 않도록 별도의 구성을 사용합니다.

테스트용 데이터베이스: 기본적으로 Laravel은 메모리 내 데이터베이스(:memory:)를 사용합니다. 디스크에 아무것도 쓸 필요가 없기 때문에 가장 빠른 방법입니다. 데이터베이스는 테스트 전에 생성되고 테스트 후에 파괴됩니다. 이를 위해 아무것도 설정할 필요조차 없습니다!

테스트 파일 생성: 행성과 관련된 테스트를 위한 특별한 파일을 만들어 봅시다.

php artisan make:test PlanetApiTest

이 명령은 tests/Feature/PlanetApiTest.php 파일을 생성합니다. Feature라는 단어는 우리가 전체 기능(예: "사용자가 행성을 생성할 수 있는가?")을 테스트하고, 개별적인 작은 클래스를 테스트하는 것이 아님을 의미합니다.


3. 테스트의 해부학: 준비, 실행, 검증

tests/Feature/PlanetApiTest.php를 엽니다. 그 안에 첫 번째 테스트를 작성할 것입니다. 좋은 테스트는 항상 세 부분(Arrange, Act, Assert)으로 구성됩니다.

<?php

namespace Tests\Feature;

use App\Models\Planet; // 모델을 임포트하는 것을 잊지 마세요
use Illuminate\Foundation\Testing\RefreshDatabase; // 가장 중요한 도구!
use Tests\TestCase;

class PlanetApiTest extends TestCase
{
    // 이 트레이트는 "마법처럼"
    // 각 테스트 전에 테스트 데이터베이스를 정리하고 다시 생성합니다.
    // 이는 테스트들이 서로 영향을 주지 않도록 보장합니다.
    use RefreshDatabase;

    /**
     * 테스트: 행성 목록을 가져오는 엔드포인트가 올바르게 작동합니다.
     * 테스트 이름은 의미가 있어야 합니다!
     */
    public function test_can_get_all_planets(): void
    {
        // 1. 준비 (Arrange)
        // 테스트 데이터베이스에 가짜 행성 3개를 생성합니다
        // 이전에 생성한 팩토리를 사용하여.
        Planet::factory()->count(3)->create();

        // 2. 실행 (Act)
        // API에 실제 GET 요청을 시뮬레이션합니다.
        $response = $this->getJson('/api/planets');

        // 3. 검증 (Assert)
        // 모든 것이 제대로 되었는지 확인합니다.
        $response->assertStatus(200); // 서버가 "200 OK"로 응답했는지 확인합니다
        $response->assertJsonCount(3); // 응답에 정확히 3개의 행성이 있는지 확인합니다
    }
}
핵심 사항:

  • use RefreshDatabase: 이 트레이트는 당신의 가장 친한 친구입니다. 각 테스트가 "깨끗한 상태" 즉, 비어있는 데이터베이스로 시작하도록 보장합니다.
  • Planet::factory(): 팩토리는 테스트 데이터를 생성하는 데 이상적입니다.
  • $this->getJson(): 이것은 테스트 내에서 API 요청을 보내기 위한 Laravel의 특별한 메서드입니다.
  • assert...(): 이것은 "어설션" 또는 "검증"입니다. 이들 중 하나라도 실패하면 테스트는 통과하지 못합니다.

4. 주요 작업 (CRUD) 테스트

행성을 생성, 업데이트 및 삭제하는 테스트를 작성해 봅시다.

A. 행성 생성 테스트 (POST)

<?php
public function test_can_create_a_planet(): void
{
    // 1. 준비: 새 행성 데이터를 준비합니다
    $planetData = [
        'name' => 'Kepler-186f',
        'description' => 'Первая экзопланета размером с Землю в обитаемой зоне.',
        'size_km' => 14000,
        'solar_system' => 'Kepler-186'
    ];

    // 2. 실행: 데이터와 함께 POST 요청을 보냅니다
    $response = $this->postJson('/api/planets', $planetData);

    // 3. 검증
    $response->assertStatus(201); // "201 Created" 상태를 예상합니다
    $response->assertJsonFragment(['name' => 'Kepler-186f']); // 응답에 생성된 이름이 있는지 확인합니다

    // 가장 중요한 검증: 데이터가 실제로 데이터베이스에 들어갔는가?
    $this->assertDatabaseHas('planets', [
        'name' => 'Kepler-186f'
    ]);
}

B. 행성 삭제 테스트 (DELETE)

<?php
public function test_can_delete_a_planet(): void
{
    // 1. 준비: 삭제할 행성을 생성합니다
    $planet = Planet::factory()->create();

    // 2. 실행: DELETE 요청을 보냅니다
    $response = $this->deleteJson("/api/planets/{$planet->id}");

    // 3. 검증
    $response->assertStatus(204); // "204 No Content"를 예상합니다 - 성공적인 삭제

    // 레코드가 데이터베이스에서 실제로 사라졌는지 확인합니다
    $this->assertDatabaseMissing('planets', [
        'id' => $planet->id
    ]);
}


5. "잘못된" 시나리오 테스트

성공적인 경우를 테스트하는 것은 좋습니다. 하지만 오류를 테스트하는 것이 훨씬 더 중요합니다!

A. 유효성 검사 오류 테스트

<?php
public function test_creation_fails_with_invalid_data(): void
{
    // 2. 실행: 의도적으로 잘못된 데이터를 보냅니다
    $response = $this->postJson('/api/planets', ['name' => '']); // 빈 이름

    // 3. 검증
    $response->assertStatus(422); // "422 Unprocessable Entity"를 예상합니다
    $response->assertJsonValidationErrors('name'); // 'name' 필드에 오류가 있을 것으로 예상합니다
}

B. "찾을 수 없음" (404) 테스트

<?php
public function test_returns_404_for_non_existent_planet(): void
{
    // 2. 실행: 존재하지 않는 ID로 행성을 요청합니다
    $response = $this->getJson('/api/planets/99999');

    // 3. 검증
    $response->assertStatus(404); // "404 Not Found"를 예상합니다
}


6. 테스트 실행

이제 테스트가 작성되었으니, 실행하는 것은 매우 간단합니다. 터미널에서 다음을 실행하세요:

php artisan test

Laravel은 모든 테스트를 찾아 하나씩 실행합니다. 모든 것이 성공적으로 통과하면 녹색 출력을 볼 수 있습니다. 어떤 테스트라도 실패하면 오류에 대한 자세한 설명과 함께 빨간색 출력이 표시되어 신속하게 수정할 수 있습니다.

특정 파일 하나만 실행하려면:

php artisan test tests/Feature/PlanetApiTest.php


8. 코드 커버리지 (Code Coverage)

단계 1: Xdebug 설치

코드 커버리지 정보를 수집하려면 PHP 확장인 Xdebug가 필요합니다.

wizard에 php -i 결과를 보내고 지침을 따르세요.

단계 2: phpunit.xml 설정

<phpunit ... >
    <coverage processUncoveredFiles="true">
        <include>
            <directory suffix=".php">./app</directory>
        </include>
    </coverage>
</phpunit>

단계 3: 보고서와 함께 실행

php artisan test --coverage-html=coverage
보고서: 브라우저에서 coverage/index.html을 엽니다


9. Postman과의 통합

Newman을 통한 자동화:

  1. Postman 컬렉션을 tests/Postman/SpaceApi.postman_collection.json으로 내보냅니다
  2. Newman 설치:
    npm install -g newman
    
  3. composer.json에 스크립트 추가:
    "scripts": {
        "test:postman": "newman run tests/Postman/SpaceApi.postman_collection.json"
    }
    
  4. 실행:
    composer test:postman
    

개념 확립을 위한 퀴즈

1. 테스트 클래스를 생성하는 명령어:

2. RefreshDatabase 트레이트는 다음 용도로 사용됩니다:

3. JSON 구조를 확인하는 메서드:

4. Laravel에서 팩토리는 다음 용도로 필요합니다:

5. CLI에서 Postman 컬렉션을 실행하는 도구:


🚀 장 요약:

사전 비행 테스트의 전체 주기를 완료했습니다! 이제 귀하의 API는 다음을 수행합니다:

  • ✅ 손쉽게 테스트 환경 설정
  • 🛡️ "준비-실행-검증" 원칙에 따라 테스트 작성.
  • 📊 성공적인 시나리오(CRUD)와 오류(유효성 검사, 404)를 모두 테스트.
  • 🔁 단일 명령어로 테스트를 실행하고 코드에 대한 확신을 가짐.

우주선 발사 준비 완료! Laravel에서 API를 생성하는 섹션을 완료했습니다.

📌 최종 확인:

  1. php artisan test를 실행하세요.
  2. 모든 테스트가 통과하는지 확인하세요 (초록불!).
  3. 코드 커버리지 보고서를 확인하세요.

⚠️ 테스트가 실패할 경우:

  • Postman을 통해 API 작동을 확인하세요.
  • 테스트 DB가 설정되어 있는지 확인하세요.
  • dd($response->content())를 사용하여 디버깅하세요.

2장 완료를 축하합니다! API를 생성했을 뿐만 아니라, 향후 미션을 위한 신뢰할 수 있고 검증된 "우주선"을 만들었습니다.

🌌 다음 단계:

  1. 인증 설정 (Sanctum)
  2. Swagger를 사용한 API 문서화
  3. 서버 배포 (Forge, VPS)
  4. Vue/React로 프런트엔드 작성

우주 미션의 성공적인 발사를 기원합니다! 다음 장에서는 API를 처음부터 작성하는 방법을 살펴보겠습니다 🚀