【baserCMS】CMS ではじめるお手軽 TDD 入門

# はじめに
この記事は[【 baserCMS 】 Advent Calendar 2021](/advent-calendar/2021/basercms) の16日目の記事です。

最近の開発では設計だけでなく TDD (テスト駆動開発) といった開発の手法なんかも注目されていますよね。
開発手法についても学習したいなと色々情報を見てみるも、読んでるだけだとイメージしにくいし、かと言って手を動かす環境を用意するのもなかなか億劫……

そんなあなたに朗報！ CMS を使うと簡単に環境を用意できる上に、テストする機能も備わっているのです！
そして何より一番嬉しいのが既にリリースし使われているサービスなのでサンプル付き！

ということで今回は **baserCMS** という CMS のサービスを使って簡単なテストを実装し、お手軽 TDD 入門をしていきましょう。

## baserCMS とは
[baserCMS](https://basercms.net/)  は国産のオープンソース CMS (Content Management System) です。
PHP で動く CMS で CakePHP というフレームワークをベースとしています。 CakePHP はコーディング規約がしっかりしているので読みやすく書きやすいのが特徴です。
baserCMS の 2021年12月現在のメインバージョンは baserCMS4 で CakePHP2 で動いています。その為、本記事では baserCMS4 (CakePHP2) を例に記述します。現在 CakePHP4 対応も進めているので CakePHP4 で試したい方は[こちら](https://baserproject.github.io/5/ucmitz/development/test/unittest)をご参照ください。
そして何よりオープンソースで無料で使えるので気軽に試すことができ、今回のような学習にも打ってつけです！

# baserCMS4 の構成
テストコードを書き始める前に baserCMS4 の構成をご紹介します。まずはどこにどんなコードを置くかのイメージをしていきましょう。

```:baserCMS4のテストの構成
/app/
    Test/
        Case/
        Fixture/
/lib/Baser/
     Test/
        Case/
        Fixture/
```

## baserCMS4 の構成の特徴
はじめに baserCMS4 そのものの構成を簡単に紹介します。
大きな特徴として `app/` `lib/` という二つの領域に分かれています。
`lib/` が baserCMS や CakePHP の本体のプログラムが置かれている領域で、 `app/` は独自のプログラムやカスタマイズしたプログラムを置く領域です。 `app/` の面白いところは `app/` 配下に `lib/` 配下と同じディレクトリ構成でファイルを置くと `app/` のファイルが優先して読み込まれ実行されます。
その為、学習用のテストコードは `app/` 配下に置くようにしましょう。元々用意されている `lib/` 配下のテストコードを書き換えて試す場合も `app/` 配下に複製して試すと本体のコードを残したまま学習ができます。

## Case
`Case/` はテストコードを置く領域です。
CakePHP は MVC の設計になっており、 `Test/` 以外にも `Controller` `Model` `View` 等の領域が用意されています。そして `Case/` 配下もテストしたい対象に合わせて領域が分かれています。
※ 今回はわかりやすく `Controller` `Model` `View` だけにしています。

```
Test/Case/
    Controller/
    Model/
    View/
```
例えば SampleController のテストは `app/Test/Case/Controller/SampleControllerTest.php` に実装します！

## Fixture
`Case/` 配下にテストコードを用意すれば簡単なテストを実装することができます！が、特定の条件に対して動作確認したいというケースも多々あると思います。
そんな時はテストケースを再現する為のテストデータを用意する必要があります。そのようなデータを作るプログラムを置く領域が `Fixture/` 配下です！
これで複雑なテストもできるようになります。

# テスト実装
ここからが大本命のテスト実装です！
ここでは学習用に簡単なテストコードを実装します。分かりやすさを重視する為に baserCMS の機能とは関係ない内容です。

## テストコード
下記のテストコードを `app/Test/Case/Controller/SampleControllerTest.php` として用意します。

```php
class SampleControllerTest extends ControllerTestCase
{
    public function setUp()
    {
        // テスト実行前に実行したい処理
    }

    public function tearDown()
    {
        // テスト実行後に実行したい処理
    }

    public function testSample1()
    {
        $expected = 'baserCMS';
        $actual = 'TDD';
        $this->assertSame($expected, $actual);
    }

    /**
     * @test
     */
    public function sample2()
    {
        $expected = 'baserCMS';
        $actual = 'TDD';
        $this->assertSame($expected, $actual);
    }
}
```
上記コードの `testSample1()` がメインのテストコードです。
今回は `$this->assertSame($expected, $actual)` という値を比較するテストを行います。テスト内容は `$expected と $actual の値が同じであればテスト成功` というものです。
上記では `$expected = 'baserCMS'` `$actual = 'DDD'` と変数の値が異なる為、テスト失敗となります。

テストコードはいくつも用意することができます。その時に用意したメソッドをテストコードとして動かす為にはルールがあります。
2つの方法があり、1つはメソッド名を `testSample1()` のように `test` で始めることです。もう一つは `sample2()` のように PHPDoc に `@test` のアノテーションを書くことです。
このどちらかに準拠することでテストコードと判定されテストが実行されます。

`setUp()` `tearDown()` はテスト前後に実行されるメソッドです。 `setUp()` ではテストケースの準備や `tearDown()` ではテスト実行結果に対する事後処理を書きます。

## テストメソッド
上記のようなテストコードを実装する為に様々なメソッドが用意されています。

|メソッド|テスト内容|
|:--|:--|
|\$this->assertSame(\$expected, \$actual)|\$actual と \$expected が型を含めて同じ値か検証|
|\$this->assertNotSame(\$expected, \$actual)|\$actual と \$expected が型を含めて異なる値か検証|
|\$this->assertTrue(\$actual)|\$actual が true であるか検証|
|\$this->assertEmpty(\$actual)|\$actual が空であるか検証|
|\$this->testAction(\$ulr, ['data'=>\$data, 'method'=>'get'])|\$url へのリクエストをシュミレート|
上記は極々一部で、baserCMS のテストにはこれ以外にもたくさんの便利なメソッドが用意されています。
PHPUnit のメソッドや CakePHP のメソッドもあるので下記を参照ください。

- [1. アサーション &mdash; PHPUnit latest Manual](https://phpunit.readthedocs.io/ja/latest/assertions.html)
- [テスト - 2.x](https://book.cakephp.org/2/ja/development/testing.html)

## テストデータ用意
テストデータを用意する方法もご紹介します。
`Test/Fixture/` 配下に用途に応じてファイルを設置します。
例えば Sample モデルのデータを用意する場合は `app/Test/Fixture/Model/SampleFixture.php` といった感じです。
今回は DB に `sample` テーブルがあり、下記構成のデータを用意する想定で説明します。

|id|key|value|
|:-:|:-:|:-:|
|1|test1|baserCMS|
|2|test2|TDD|

```php
class SampleFixture extends CakeTestFixture
{

    public $import = 'Sample';

    public $records = [
        [
            'id' => 1,
            'key' => 'test1',
            'value' => 'baserCMS'
        ],
        [
            'id' => 2,
            'key' => 'test2',
            'value' => 'TDD'
        ]
    ];
}
```

`$import = 'Sample'` はメインロジックの Sample を参考にし、そこからテーブルを生成する処理です。この記述を書くことでテーブル定義から書く必要がなくなります。
`$records` は DB に挿入したいデータの配列です。カラム名に合わせキーを設定し、用意するデータ数分の配列を用意します。

```php
class SampleControllerTest extends ControllerTestCase
{
    public $fixture = ['app.Model.Sample'];
}
```

用意した Fixture はテストケースで上記のように `$fixture` に記述すると読み込まれます。

## テスト実行
最後にお待ちかね！テストを用意したので実際に動かします。
サーバや Docker 等に入り CLI から実行します。

```
$ cd [app/ のディレクトリ]
$ ./Console/cake baser_test baser
```

上記コマンドを実行することで対話形式でテストを実行することができます。
部分的にテストを実行する場合は下記のように行います。

```
$ ./Console/cake baser_test baser Controller/SampleController --filter testSample
```

テストしたいクラスを指定したり `--filter` でメソッドも指定することができます。
コマンド実行後はテストが順次実行され、成功時は `.`、失敗時は `F`、プログラムエラー時は `E` が出ます。
全てのテストメソッドが `.` になれば全テスト成功、問題がないことになりテストも完了です。

# まとめ
今回は TDD が気になる人に向けて簡単に環境を用意して動かす方法をご紹介しました！
実際にテストコードを書くことでどのようなテストができるのかのイメージがしやすくなったと思います。
ここで書いたものは本当に触りの入門ですが、他にもご自身でコードを書き換えながら色々と試してみてもらえたらと思います。
皆さんの楽しいテスト駆動ライフを応援しています。

# 参考
- [baserCMS](https://basercms.net/) 
- [baserCMS Wiki テストコードの追加と実行](https://github.com/baserproject/basercms/wiki/%E3%83%86%E3%82%B9%E3%83%88%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E8%BF%BD%E5%8A%A0%E3%81%A8%E5%AE%9F%E8%A1%8C)
- [PHPUnit](https://phpunit.readthedocs.io/ja/latest/)

---
[【 baserCMS 】 Advent Calendar 2021](/advent-calendar/2021/basercms)
◀︎ 15日目 [ざっくりcakephp2 vs cakephp4の違い](/humuhimi/items/b43eeef355c1c8a9b31b) @humuhimi さん
▶︎ 17日目 [baserCMS発行のベーサーメルマガをご存知ですか？](https://basercms.net/news/archives/748) @baserCMS さん