CodeIgniter4のREST APIのテストを書く

この記事は CodeIgniter Advent Calendar 2020 - Qiita の21日目です。まだ、空きがありますので、興味のある方は気軽に参加してください。

今日は昨日作成した CodeIgniter4 の REST API のテストコードを作成してみます。

CodeIgniter4のフィーチャーテスト も参考にしてください。

動作確認環境

  • CodeIgniter 4.0.5 開発版
  • PHP 7.4.13
  • MySQL 5.7.32
  • macOS 10.15.7

シーダーの準備

News テーブルの状態を同一にするシーダーを以下のように作成します。

tests/_support/Database/Seeds/NewsSeeder.php

<?php

namespace Tests\Support\Database\Seeds;

use CodeIgniter\Database\Seeder;

class NewsSeeder extends Seeder
{
    public function run()
    {
        $table = 'news';

        $this->db->table($table)->truncate();

        $data = [
            [
                'title' => 'Elvis sighted',
                'slug' => 'elvis-sighted',
                'body' => 'Elvis was sighted at the Podunk internet cafe. It looked like he was writing a CodeIgniter app.',
            ],
        ];
        $this->db->table($table)->insertBatch($data);
    }
}

まず、CodeIgniter4 のメソッドを使い、テーブルを truncate します。

$this->db->table($table)->truncate();

そして、レコードを 1件挿入します。

$this->db->table($table)->insertBatch($data);

このシーダーを実行すれば、テーブルの状態が同じになります。

フィーチャーテストの作成

テストファイルの作成

tests/feature/Api/ フォルダを追加して、NewsTest.php を作成します。

tests/feature/Api/NewsTest.php

<?php

namespace Tests\Feature\Api;

use Tests\Support\Database\Seeds\NewsSeeder;
use CodeIgniter\Test\FeatureTestCase;

class NewsTest extends FeatureTestCase
{
    protected $refresh = false;
    protected $namespace = 'App';
}

App\Database\Migrations 以下のマイグレーションファイルを使い、テストごとにデータベースをリフレッシュする(バージョン 0 まで戻し再度最新バージョンまでマイグレーションする)ことはしないように設定しています。

シーダーを実行するメソッドの追加

現状、CodeIgniter4 の FeatureTestCase には自動的にシーダーを 1回だけ実行する方法がありません。

(2021-02-23 追記) CodeIgniter 4.0.5以降にはマイグレーションを実行しない設定やマイグレーションやシーダーを一度だけ実行する設定が追加されました。

そこで、シーダーを実行するメソッドをテストファイルに追加します。

    private function runSeeder()
    {
        $this->seeder->setPath(rtrim($this->basePath, '/') . '/Seeds');
        $this->seed(NewsSeeder::class);
    }

GET api/news

全ての記事を取得する API のテストです。

最初のテストです。ここでシーダーを実行します。

    public function test_get_api_news()
    {
        $this->runSeeder();

        $result = $this->get('api/news');

        $result->assertStatus(200);

        $result->assertJSONFragment(
            [
                'news' => [
                    ['title' => 'Elvis sighted'],
                ]
            ]
        );

        $json = $result->getJSON();
        $this->assertJsonStringEqualsJsonString(
            '{
                "status": 200,
                "error": null,
                "news": [
                    {
                        "id": "1",
                        "title": "Elvis sighted",
                        "slug": "elvis-sighted",
                        "body": "Elvis was sighted at the Podunk internet cafe. It looked like he was writing a CodeIgniter app."
                    }
                ]
            }',
            $json
        );
    }

CodeIgniter4 の $result->assertJSONFragment() は、JSON にデータが含まれるかどうか確認するメソッドです。

CodeIgniter4 の $result->getJSON() で、レスポンスの JSON 文字列を取得できます。

GET api/news/{id}

指定の記事を取得する API のテストです。

    public function test_get_api_news_id()
    {
        $result = $this->get('api/news/1');

        $result->assertStatus(200);

        $result->assertJSONFragment([
            'news' => [
                'title' => 'Elvis sighted',
            ],
        ]);
    }

POST api/news

記事を新規作成する API のテストです。

    public function test_post_api_news()
    {
        $params = [
            'title' => 'New news',
            'body' => 'This is a new news.',
        ];
        $result = $this->post('api/news', $params);

        $result->assertStatus(201);

        $this->seeInDatabase('news', [
            'title' => 'New news',
        ]);
    }

これで id=2 のニュースが作成されます。

CodeIgniter4 の $this->seeInDatabase() メソッドで、含まれるデータを確認します。

PUT api/news/{id}

記事を更新する API のテストです。

    public function test_put_api_news_id()
    {
        $params = [
            'title' => 'Updated new news',
            'body' => 'This is an updated new news.',
        ];
        $result = $this->withBody(http_build_query($params))
            ->put('api/news/2', $params);

        $result->assertStatus(200);

        $this->dontSeeInDatabase('news', [
            'title' => 'New news',
        ]);
        $this->seeInDatabase('news', [
            'title' => 'Updated new news',
        ]);
    }

CodeIgniter4 の $this->dontSeeInDatabase() メソッドで、データベースに含まれないデータを確認します。

DELETE api/news/{id}

記事を削除する API のテストです。

    public function test_delete_api_news_id()
    {
        $result = $this->delete('api/news/2');

        $result->assertStatus(200);

        $this->dontSeeInDatabase('news', [
            'title' => 'Updated new news',
        ]);
    }

テストの実行

テストを実行します。

$ vendor/bin/phpunit tests/feature/Api/NewsTest.php 
PHPUnit 8.5.13 by Sebastian Bergmann and contributors.

Error:         XDEBUG_MODE=coverage or xdebug.mode=coverage has to be set

.....                                                               5 / 5 (100%)

Time: 510 ms, Memory: 10.00 MB

OK (5 tests, 14 assertions)

通りました!

この記事は CodeIgniter Advent Calendar 2020 - Qiita の21日目です。まだ、空きがありますので、興味のある方は気軽に参加してください。

参考

Date: 2020/12/21

Tags: codeigniter, codeigniter4, database, rest, testing