CodeIgniter 3.0でPHPUnitを使う

CodeIgniter 2.xの時代にはCIUnitというツールを使い、CodeIgniterでPHPUnitによるテストを書いていました。

CodeIgniter 3.0時代になり状況がどう変わったかというと、CodeIgniter本体のテストは進んだようですが、アプリケーションのテストをどうするかという問題は公式にはとくに変化はないようです。

そして、実際にどのようにしているかについては、割と混沌としていました。

以上のような方法・ツールがあるようです。

個人的にできるだけCodeIgniter本体に手を入れずにPHPUnitを使いたいと考えていましたが、これだというものはありませんでした。

ci-phpunit-test

そこで「ci-phpunit-test」というツールを作成しました。

インストール方法

ダウンロード

(2015-06-12 更新)

GitHubから最新版(https://github.com/kenjis/ci-phpunit-test/releases)をダウンロードして展開します。

以下のようなフォルダ構成になっています。このapplication/testsフォルダを自分のCodeIgniterプロジェクトのapplication/testsとしてコピーします。

ci-phpunit-test/
├── application/
│   ├── database/
│   ├── helpers/
│   ├── libraries/
│   └── tests/
├── bin/
└── docs/

applicationフォルダのその他のファイルはサンプルです。必要に応じてCodeIgniterプロジェクトにコピーしてください(後述)。

パスの調整

(2015-06-15 追記) この手順はci-phpunit-test v0.1.1以降不要になりました。

ci-phpunit-testはデフォルトでは、CodeIgniter Composer Installerによる以下のフォルダ構成を前提としています。

codeigniter/
├── application/
├── public/
│   └── index.php
└── vendor/
    └── codeigniter/
        └── framework/
            └── system/

フォルダ構成が違う場合(CodeIgniterのデフォルトのフォルダ構成の場合を含む)、application/tests/Bootstrap.phpファイルをエディタで開き、以下のパスを調整してください。

    $system_path = '../../vendor/codeigniter/framework/system';

    $application_folder = '../../application';

    define('FCPATH', realpath(dirname(__FILE__).'/../../public').'/');

FCPATHindex.phpがあるフォルダです。

(2015-06-12 追記)

CodeIgniter標準のフォルダ構成の場合は、以下のように変更します。

--- a/application/tests/Bootstrap.php
+++ b/application/tests/Bootstrap.php
@@ -102,7 +102,7 @@ switch (ENVIRONMENT)
  * Include the path if the folder is not in the same directory
  * as this file.
  */
-   $system_path = '../../vendor/codeigniter/framework/system';
+   $system_path = '../../system';

 /*
  *---------------------------------------------------------------
@@ -230,7 +230,7 @@ switch (ENVIRONMENT)
    define('BASEPATH', str_replace('\\', '/', $system_path));

    // Path to the front controller (this file)
-   define('FCPATH', realpath(dirname(__FILE__).'/../../public').'/');
+   define('FCPATH', realpath(dirname(__FILE__).'/../..').'/');

    // Name of the "system folder"
    define('SYSDIR', trim(strrchr(trim(BASEPATH, '/'), '/'), '/'));

これでインストール完了です。

テストの実行方法

PHPUnitは別途インストールしてください。

$ cd /path/to/codeigniter/
$ cd application/tests/
$ phpunit
PHPUnit 4.1.6 by Sebastian Bergmann.

Configuration read from /.../codeigniter/application/tests/phpunit.xml

.

Time: 470 ms, Memory: 3.50Mb

OK (1 test, 1 assertion)

Generating code coverage report in Clover XML format ... done

Generating code coverage report in HTML format ... done

テストの書き方

モデル

(2015-08-15 追記) setUp()メソッドのコードを更新しました。

tests/models/Inventory_model_test.php

<?php

class Inventory_model_test extends TestCase
{
    public function setUp()
    {
        $this->resetInstance();
        $this->CI->load->model('shop/Inventory_model');
        $this->obj = $this->CI->Inventory_model;
    }

    public function test_get_category_list()
    {
        $expected = [
            1 => 'Book',
            2 => 'CD',
            3 => 'DVD',
        ];
        $list = $this->obj->get_category_list();
        foreach ($list as $category) {
            $this->assertEquals($expected[$category->id], $category->name);
        }
    }

    public function test_get_category_name()
    {
        $actual = $this->obj->get_category_name(1);
        $expected = 'Book';
        $this->assertEquals($expected, $actual);
    }
}

テストケースクラスはTestCaseクラスを継承します。

setUpBeforeClass()メソッドをオーバーライドした場合は、忘れずにparent::setUpBeforeClass();を追加してください。

データベースシーディング

ダウンロードしたファイルのapplication/libraries/Seeder.phpapplication/database/seeds/CategorySeeder.phpにサンプルコードが含まれています。

インストールされてないので、使いたい場合は手動でコピーしてください。

Seederクラスは以下のように使用します。

    public static function setUpBeforeClass()
    {
        parent::setUpBeforeClass();

        $CI =& get_instance();
        $CI->load->library('Seeder');
        $CI->seeder->call('CategorySeeder');
    }

コントローラ

(2017-02-15 追記) テストコードを更新しました。

tests/controllers/Welcome_test.php

<?php

class Welcome_test extends TestCase
{
    public function test_index()
    {
        $output = $this->request('GET', 'welcome/index');
        $this->assertContains('<title>Welcome to CodeIgniter</title>', $output);
    }
}

TestCaseクラスには$this->request()メソッドが定義されています。

他のサンプル

もっとテストを見たい場合は、以下のアプリのテストを参照願います。

なお、このアプリのコードレビューも募集しています。

まとめ

  • ci-phpunit-testを使うと簡単にCodeIgniter 3.0でPHPUnitのテストを書くことができます
  • CodeIgniter本体のファイルは一切変更しません

(とはいえ、実は内部的にはCodeIgniterのクラスや関数を一部変更しています)

もっと知るには?

(2015-08-25 追記)

CodeIgniter 3.0でのPHPUnitおよびci-phpunit-testの使い方について、もっと知りたい方は以下の記事もご覧下さい。

関連

Date: 2015/05/19

Tags: codeigniter, phpunit, testing, database