【CakePHP4入門】phpUnitでTableクラスのユニットテスト作成

phpUnitでCakePHP4のTableクラスのユニットテストを作成する

phpUnitを使ってCakePHPのユニットテストを行う方法について調べました。
今回はTableクラスのユニットテスト作成をしてみます。

まず以下のテーブルに対応したモデルクラスの「CompaniesTable」と「Company」を作成します。

> desc companies;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | int(11)      | NO   | PRI | NULL    | auto_increment |
| name  | varchar(255) | YES  |     | NULL    |                |
+-------+--------------+------+-----+---------+----------------+

CompaniesTable.php:(テーブルクラス。必要な部分のみ抜粋)

<?php
namespace App\Model\Table;

class CompaniesTable extends Table
{
    public function initialize(array $config): void
    {
        parent::initialize($config);

        $this->setTable('companies');
        $this->setDisplayField('name');
        $this->setPrimaryKey('id');
    }
    public function validationDefault(Validator $validator): Validator
    {
        $validator
            ->integer('id')
            ->allowEmptyString('id', null, 'create');

        $validator
            ->scalar('name')
            ->maxLength('name', 255)
            ->allowEmptyString('name');

        return $validator;
    }
}

Company.php:(エンティティクラス。必要な部分のみ抜粋)

<?php
use Cake\ORM\Entity;
class Company extends Entity
{
    protected $_accessible = [
        'name' => true,
    ];
}

bakeコマンドでテストを作成すると以下のようなテストクラスが生成されます。

<?php
namespace App\Test\TestCase\Model\Table;

use App\Model\Table\CompaniesTable;
use Cake\TestSuite\TestCase;

class CompaniesTableTest extends TestCase
{
    protected $Companies;
    protected $fixtures = [
        'app.Companies',
    ];

    public function setUp(): void
    {
        parent::setUp();
        $config = $this->getTableLocator()->exists('Companies') ? [] : ['className' => CompaniesTable::class];
        $this->Companies = $this->getTableLocator()->get('Companies', $config);
    }

    public function tearDown(): void
    {
        unset($this->Companies);
        parent::tearDown();
    }

    public function testValidationDefault(): void
    {
        $this->markTestIncomplete('Not implemented yet.');
    }
}

各メソッドの役割は、次のようになります。
・setUpメソッド:テスト前の初期設定
・tearDownメソッド:テスト後の切り戻し処理
・testValidationDefaultメソッド:テスト内容の記述

testValidationDefaultメソッドにテスト内容を記述してみます。
例えば、「name」の値は255以内なので、256文字でエラーが表示されるかをチェックするテストケースを作成します。

まず、testValidationDefaultメソッドの内容を以下のようにします。

    $testCompanyEntity = $this->Companies->newEntity([
            'id' => 1,
            'name' => str_repeat('a', 256),
        ]);
        $expectErrorMessage = [];
        $this->assertSame($expectErrorMessage , $testCompanyEntity ->getErrors());

assertSameというメソッドは、第一引数の値と第二引数の値が同じかどうかをチェックするメソッドです。
同じであればテストが成功、異なれば失敗となります。

今回はnewEntityメソッドを使って生成したCompanyエンティティのname属性に、256文字の値を設定しようとしているので、
getErrorsメソッドの実行結果は何かしらのエラーが取得されるはずですが、想定される内容($expectErrorMessage)には、空配列を指定しています。

この状態で以下のコマンドでテストを実行してみます。

$ ./vendor/bin/phpunit tests/TestCase/Model/Table/CompaniesTableTest.php
PHPUnit 8.5.8 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 683 ms, Memory: 10.00 MB

There was 1 failure:

1) App\Test\TestCase\Model\Table\CompaniesTableTest::testValidationDefault
Failed asserting that two arrays are identical.
--- Expected
+++ Actual
@@ @@
-Array &0 ()
+Array &0 (
+    'name' => Array &1 (
+        'maxLength' => 'The provided value is invalid'
+    )
+)

実行結果を見てみると、「F」と表示されているのはテストが失敗したという意味になります。
失敗の内容が下の方に書かれている通り、「$testCompanyEntity ->getErrors()」の実行結果が想定結果と異なっているということになり、テストが通っていないということになります。

では、「$expectErrorMessage = [];」の箇所を以下のように変更してみます。

    $expectErrorMessage = [
        'name' => ['maxLength' => 'The provided value is invalid'],
    ];

再度テストを実行してみると、実行結果が「OK」になります。

このようにしてTableクラスのテストを作成・実行することができます。