CodeIgniter3 + PHPUnit 9.4.0 + ci-phpunit-test dev-2.x を利用した Unit Test環境の整備

# 概要

最近少しずつPHPの勉強を進めていまして、CodeIgniter3のフレームワークを利用した、
ちょっとしたWebアプリを練習で構築中です。
個人的にはJavaが得意なのですが、Javaのときには自然と作っていたテストクラスを、PHPでもそろそろ作りたいなと思って、見つけたのが`ci-phpunit-test`でした。

今回その環境を構築して、単純なテストを1つだけ作って確認するまでをまとめました。
※PHPUnitが9.4.0と最新バージョンになっていることで、非常に環境構築に苦労がありましたので、その辺の右往左往など解決に至るまでダラダラと時系列にメモとして残しています。

# PHPUnitのセットアップ

まずはPHPUnitのセットアップです。
ここでは、composerを利用してphpunitを現在構築中のアプリケーションにセットアップしていきます。

アプリケーションのルートフォルダは`/var/www/html/codeiogniter3`としていますので、基本的にはここをルートとして作業を進めていきます。

```shell-session
# cd /var/www/html/codeigniter3/
# composer require --dev phpunit/phpunit
# vendor/bin/phpunit --version
PHPUnit 9.4.0 by Sebastian Bergmann and contributors.
```

上記作業でPHPUnitのバージョンは`9.4.0`がセットされました。

# ci-phpunit-testのセットアップ

普通にgithubの
https://github.com/kenjis/ci-phpunit-test#installation-via-composer
をそのままトレースして環境構築を進めていきます。
※ここでの手順は最終的に失敗に終わりますので、ダラダラとした内容に興味が無い方は飛ばして下さい。

```shell-session
# composer require kenjis/ci-phpunit-test --dev
# php vendor/kenjis/ci-phpunit-test/install.php --from-composer
↑これを実行すると、application/tests/*** にいろんなソースがコピーされます。
```

# phpunitのサンプル実行を試す

上記までで一通りのセットアップが完了したので、application/tests/配下にcdして、phpunitを実行します。

```shell-session
# cd /var/www/html/codeigniter3/application/tests/
# ../../vendor/bin/phpunit

Fatal error: Declaration of CIPHPUnitTestCase::setUpBeforeClass() must be compatible with PHPUnit\Framework\TestCase::setUpBeforeClass(): void in /var/www/html/codeigniter3/application/tests/_ci_phpunit_test/CIPHPUnitTestCase.php on line 75
```

上記のように、Fatal errorという無視出来ないエラーが発生してしまいました。
この内容をみていると、どうやらfunctionの戻り値の型をちゃんと指定しなさい。と怒っているようです。

調べていると以下の記事がありました。
https://qiita.com/stoneBK7/items/fcc898f38ee161b38ef4

どうやら、PHPのバージョンが7.0を超えたあたりから、型宣言が可能となり、PHPUnit8.0以降からは、それに追随して型宣言しないといけないような仕様に変わったみたいです。

もう少し粘ってみたいと思いますので、原因となっているソースコードの部分を修正してみます。

```php:/var/www/html/codeigniter3/application/tests/_ci_phpunit_test/CIPHPUnitTestCase.php 
88 public static function setUpBeforeClass():void  # ← voidをつける

98 public static function tearDownAfterClass():void # ← voidをつける

105 protected function tearDown():void
```

```php:/var/www/html/codeigniter3/application/tests/_ci_phpunit_test/CIPHPUnitTestDbTestCase.php
47 protected function setUp():void

58 protected function tearDown():void
```

と色々やってみましたが、エラーが多く修正箇所も多くなってしまい、こんなん使えないんじゃね？と諦めそうになったので、
改めて公式？サイトのgithubの内容を確認してみます。
https://github.com/kenjis/ci-phpunit-test#requirements

> ・PHP 5.4.0 or later (5.6 or later is recommended)
> ・CodeIgniter 3.x
> ・PHPUnit 4.3 to 7.5 (4.8 or later is recommended)

という記載があり、今回利用しているPHPUnitの最新バージョンが9.4.0のため、問題がありそうです。
色々探していたら、
https://github.com/kenjis/ci-phpunit-test/tree/2.x
が見つかりました。

正式リリースのものでは無いんだと思いますが、ここまできたら、とりあえず試してみようと思います。

# ci-phpunit-test 2.x を試す

とりあえずzipをダウンロードして解凍して、application/tests/フォルダへ全部コピーして、
nginxで触れるようにして、権限変更して、、、ということをやります。

```shell-session
# cd /usr/local/src
# wget https://github.com/kenjis/ci-phpunit-test/archive/2.x.zip
# unzip 2.x.zip
# cd /usr/local/src/ci-phpunit-test-2.x/application
# cp -rp tests/ /var/www/html/codeigniter3/application/
# find /var/www/html/codeigniter3/application/tests -type d -exec chmod 775 {} +
# find /var/www/html/codeigniter3/application/tests -type f -exec chmod 664 {} +
# cd /var/www/html/codeigniter3/application
# chown -R nginx:nginx tests/
```

`application/tests`フォルダに移動して、phpunitを実行してみます。

```shell-session
# cd /var/www/html/codeigniter3/application/tests
# ../../vendor/bin/phpunit

...

Your system folder path does not appear to be set correctly. Please open the following file and correct this: Bootstrap.php
```

ん〜、まだ気に食わないことがあるようですね。
以下のファイルの`$system_path`の定義が悪いらしいので修正。

```php:application/tests/Bootstrap.php
$system_path = '../../vendor/codeigniter/framework/system';
```

もいっちょ実行。

```shell-session
# cd /var/www/html/codeigniter3/application/tests
# ../../vendor/bin/phpunit

...

1) Welcome_test::test_method_404
PHPUnit\Framework\TestCase::$backupGlobalsBlacklist is deprecated and will be removed in PHPUnit 10. Please use PHPUnit\Framework\TestCase::$backupGlobalsExcludeList instead.

/var/www/html/codeigniter3/vendor/phpunit/phpunit/phpunit:61

2) Welcome_test::test_APPPATH
PHPUnit\Framework\TestCase::$backupGlobalsBlacklist is deprecated and will be removed in PHPUnit 10. Please use PHPUnit\Framework\TestCase::$backupGlobalsExcludeList instead.

/var/www/html/codeigniter3/vendor/phpunit/phpunit/phpunit:61
```

上記のようなWarning？が出るので、以下を修正。

```php:application/tests/_ci_phpunit_test/CIPHPUnitTestCase.php
// 以下をコメントアウト
// protected $backupGlobalsBlacklist = ['RTR'];
```

もいっちょ実行。

```shell-session
# cd /var/www/html/codeigniter3/application/tests
# ../../vendor/bin/phpunit

...

1) Welcome_test::test_index
Failed asserting that 'Welcome/index is not found' contains "<title>Welcome to CodeIgniter</title>".

/var/www/html/codeigniter3/application/tests/controllers/Welcome_test.php:16
/var/www/html/codeigniter3/vendor/phpunit/phpunit/phpunit:61
```

単純に、いらないと思って削除してしまっていたWelcom.phpのControllerが見つからないのでテストにならないと叱られています。（これは私が悪かった。。。）
一度消してしまったので、元に戻します。

```php:application/controller/Welcom.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Welcome extends CI_Controller {

	/**
	 * Index Page for this controller.
	 *
	 * Maps to the following URL
	 * 		http://example.com/index.php/welcome
	 *	- or -
	 * 		http://example.com/index.php/welcome/index
	 *	- or -
	 * Since this controller is set as the default controller in
	 * config/routes.php, it's displayed at http://example.com/
	 *
	 * So any other public methods not prefixed with an underscore will
	 * map to /index.php/welcome/<method_name>
	 * @see https://codeigniter.com/user_guide/general/urls.html
	 */
	public function index()
	{
		$this->load->view('welcome_message');
	}
}
```

`application/views/welcome_message.php`もcomposerとかでCodeIgniter3の環境を構築した初期のものをそのまま配置します。
なくなっちゃったら`vendor/codeigniter/framework/application/views/`から再配置してください。

```shell-session
# cd /var/www/html/codeigniter3/application/tests
# ../../vendor/bin/phpunit

PHPUnit 9.4.0 by Sebastian Bergmann and contributors.

Warning:       No code coverage driver available
Warning:       Your XML configuration validates against a deprecated schema.
Suggestion:    Migrate your XML configuration using "--migrate-configuration"!

...                                                                 3 / 3 (100%)

Time: 00:00.015, Memory: 8.00 MB

OK (3 tests, 3 assertions)
```

phpでの開発を知らないので、phpunitの実行結果としてこれが正しい感じなのかは不明ですが、
嫌な感じのエラーとか出ていないので、とりあえず1つテストクラスを作って動作確認してみたいと思います。

```php:tests/Gmo_api_model_test.php
<?php

class Gmo_api_model_test extends TestCase
{
    public function setUp():void
    {
        $this->resetInstance();
        $this->CI->load->model('Gmo_api_model');
        $this->obj = $this->CI->Gmo_api_model;
    }

    // とりあえず適当に
    public function test_sample():void
    {
        $this->assertEquals('1', '1');
    }
}
```

phpunitの実行結果をHTMLファイルに出力して、ブラウザで結果を確認してみます。
（なんか今までの実行結果だけだと何が実行されてどれがOKだったのかいまいちわかりづらいので。）

```shell-session
# cd /var/www/html/codeigniter3/application/tests
# ../../vendor/bin/phpunit --testdox-html /var/www/html/codeigniter3/public/phpunit.html
```

こんな感じでHTMLで結果を確認できました。

![スクリーンショット 2020-10-07 21.05.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/68007e22-f59d-a427-6aa7-6cbae11bfa2a.png)

とりあえず一苦労しましたが、なんとかUnitTestの環境まで整えることができました。
機能が増えてくると、どうしても画面からの動作確認がダルくて、、、テストコードが書けないとこれ以上の開発を進めるのきついなぁという状況だったので、ひとまず先に進めそうな感じです。

完全に素人なので、何か問題がある手順とかやり方だったりとかするかもしれませんが、もし気になるところとか指摘があれば、優し目にご指摘いただけますと幸いです。