CI4 Playground v4.7.3
한국어문서
CI4 테스팅 기초

CodeIgniter 4는 PHPUnit 기반의 테스트 도구를 내장하고 있습니다. CIUnitTestCase를 상속하면 CI4 서비스, 헬퍼, DB에 손쉽게 접근할 수 있습니다.

단위 테스트 (Unit Test)

개별 함수나 메서드를 독립적으로 검증합니다. 외부 의존성(DB, 네트워크) 없이 빠르게 실행됩니다. CIUnitTestCase를 상속해 헬퍼·서비스·유틸을 테스트합니다.

통합 테스트 (Integration Test)

실제 DB와 연동하여 비즈니스 로직 전체를 검증합니다. DatabaseTestTrait를 사용하면 테스트마다 DB를 자동으로 초기화합니다.

기본 테스트 클래스 구조
<?php

namespace Tests\App;

use CodeIgniter\Test\CIUnitTestCase;

final class MyTest extends CIUnitTestCase
{
    protected function setUp(): void
    {
        parent::setUp();
        // 각 테스트 전에 실행
    }

    public function testSomething(): void
    {
        $this->assertSame('expected', someFunction());
    }
}
DatabaseTestTrait

DB가 필요한 테스트에는 DatabaseTestTrait를 사용합니다. 테스트용 SQLite DB에 마이그레이션을 자동 실행하고, 각 테스트 후 롤백합니다.

DatabaseTestTrait 설정
use CodeIgniter\Test\DatabaseTestTrait;

final class PostServiceTest extends CIUnitTestCase
{
    use DatabaseTestTrait;

    // 테스트 DB에 마이그레이션 자동 실행
    protected $migrate  = true;
    // 마이그레이션 파일 경로
    protected $basePath = 'tests/_support/Database';

    protected function setUp(): void
    {
        parent::setUp();
        // skipValidation(true) 으로 시드 데이터 직접 삽입
        (new PostModel())->skipValidation(true)->insertBatch([
            ['title' => '게시물 A', 'content' => '내용 A ...', 'views' => 100],
        ]);
    }
}
테스트용 마이그레이션 파일 위치
tests/_support/Database/Migrations/ 에 마이그레이션을 두면 운영 DB와 완전히 분리됩니다.
테스트 실행 명령어
전체 테스트 실행
./vendor/bin/phpunit --testdox
특정 파일만 실행
./vendor/bin/phpunit tests/app/Helpers/PlaygroundHelperTest.php --testdox
./vendor/bin/phpunit tests/app/Services/PostServiceTest.php --testdox
phpunit.xml.dist (CI4 기본 설정)
<testsuites>
    <testsuite name="App">
        <directory suffix="Test.php">./tests</directory>
    </testsuite>
</testsuites>
PlaygroundHelperTest — 단위 테스트

커스텀 헬퍼 함수 5개(format_filesize, time_ago, truncate_text, highlight_keyword, korean_number)에 대한 13개의 단위 테스트입니다.

tests/app/Helpers/PlaygroundHelperTest.php
final class PlaygroundHelperTest extends CIUnitTestCase
{
    protected function setUp(): void
    {
        parent::setUp();
        helper('playground');   // 헬퍼 로드
    }

    // format_filesize: 바이트 → 사람이 읽기 쉬운 크기 문자열
    public function testFormatFilesizeBytes(): void
    {
        $this->assertSame('512 B', format_filesize(512));
    }

    public function testFormatFilesizeKilobytes(): void
    {
        $this->assertSame('1.5 KB', format_filesize(1536));
    }

    public function testFormatFilesizeMegabytes(): void
    {
        $result = format_filesize(2097152);
        $this->assertStringContainsString('MB', $result);
        $this->assertStringContainsString('2', $result);
    }

    // truncate_text: 지정 길이 초과 시 말줄임표
    public function testTruncateTextShortString(): void
    {
        $this->assertSame('짧은글', truncate_text('짧은글', 20));
    }

    public function testTruncateTextLongString(): void
    {
        $result = truncate_text('가나다라마바사아자차카타파하가나다라마바사', 10);
        $this->assertStringEndsWith('...', $result);
        $this->assertLessThanOrEqual(13, mb_strlen($result));
    }

    // time_ago: 타임스탬프 → "N분 전" 형식
    public function testTimeAgoSeconds(): void
    {
        $this->assertStringContainsString('초 전', time_ago(time() - 30));
    }

    // korean_number: 숫자 → 만/억 단위 포맷
    public function testKoreanNumberMan(): void
    {
        $this->assertStringContainsString('만', korean_number(50000));
    }

    public function testKoreanNumberEok(): void
    {
        $this->assertStringContainsString('억', korean_number(100000000));
    }
}
PostServiceTest — 통합 테스트

DatabaseTestTrait를 사용해 실제 SQLite 테스트 DB 위에서 서비스 레이어의 동작을 검증합니다. 7개의 테스트로 구성됩니다.

tests/app/Services/PostServiceTest.php
final class PostServiceTest extends CIUnitTestCase
{
    use DatabaseTestTrait;

    protected $migrate  = true;
    protected $basePath = 'tests/_support/Database';

    private PostService $service;

    protected function setUp(): void
    {
        parent::setUp();
        $this->service = new PostService(new PostModel());

        // 테스트용 시드 데이터 직접 삽입
        (new PostModel())->skipValidation(true)->insertBatch([
            ['title' => '게시물 A', 'content' => '테스트 내용입니다 A', 'views' => 100],
            ['title' => '게시물 B', 'content' => '테스트 내용입니다 B', 'views' => 50],
            ['title' => '게시물 C', 'content' => '테스트 내용입니다 C', 'views' => 200],
        ]);
    }

    // getTopPosts: 조회수 내림차순 정렬 확인
    public function testGetTopPostsOrderedByViews(): void
    {
        $posts = $this->service->getTopPosts(5);
        if (count($posts) >= 2) {
            $this->assertGreaterThanOrEqual($posts[1]->views, $posts[0]->views);
        }
        $this->assertTrue(true);
    }

    // getSummary: 필수 키 존재 여부 확인
    public function testGetSummaryReturnsRequiredKeys(): void
    {
        $summary = $this->service->getSummary();
        $this->assertArrayHasKey('total', $summary);
        $this->assertArrayHasKey('total_views', $summary);
        $this->assertArrayHasKey('avg_views', $summary);
    }

    // search: 빈 키워드 → 빈 배열 반환
    public function testSearchReturnsEmptyForBlankKeyword(): void
    {
        $this->assertEmpty($this->service->search(''));
    }

    // create: 제목 없이 생성 시도 → 실패
    public function testCreateFailsWithMissingTitle(): void
    {
        $result = $this->service->create(['content' => '본문만 있음']);
        $this->assertFalse($result['success']);
        $this->assertArrayHasKey('errors', $result);
    }

    // create: 정상 데이터 → 성공 + id 반환
    public function testCreateSucceedsWithValidData(): void
    {
        $result = $this->service->create([
            'title'   => '테스트 게시물',
            'content' => '서비스 레이어를 통해 저장한 테스트 본문입니다.',
            'author'  => '테스트작성자',
        ]);
        $this->assertTrue($result['success']);
        $this->assertGreaterThan(0, $result['id']);
    }
}
주요 주의사항
공유 Validator 인스턴스 문제

Services::validation()은 싱글톤을 반환해 이전 테스트의 에러가 남아 있습니다. Services::validation(null, false)로 항상 새 인스턴스를 생성해야 합니다.

테스트 DB 테이블 미존재

$basePath = 'tests/_support/Database'를 지정하고 해당 경로에 테스트 전용 마이그레이션 파일을 두어야 합니다. 운영 마이그레이션과 분리하세요.

테스트 실행하기

실행할 테스트 스위트를 선택하고 PHPUnit을 실행합니다.

위 버튼을 클릭하면 실제 PHPUnit 실행 결과가 표시됩니다.