CakePHP
PHPUnit
unittest
cakephp3

CakePHP3でControllerのユニットテストを書く例

More than 3 years have passed since last update.

Controllerのテスト例を書きます。

bin/cake bake test Controller ArticlesControllerとかのbakeでファイルが生成される(Controllerのbakeでも一緒にできているはず)ので、それをベースに編集したらいいと思います。

メソッド名は『test』で始まっていれば何でも大丈夫です。(わかりやすい名前がいいと思うけど)

参考:

Cookbook 3.x テスト

PHPUnit 用のテストの書き方 - アサーション


表示できるかのテスト

まずは表示できないと始まりません。


tests/TestCase/Controller/ArticlesControllerTest.php

public function testIndex()

{
$this->get('/articles');
$this->assertResponseOk();
$this->assertResponseContains('>ログイン</a>');
$this->assertCount(10, $this->viewVariable('articles'));
}

/articlesへのGETリクエストで2xxのレスポンスが返ってくることをテストしています。

get()以外に、post()put()delete()patch()もできます。

assertResponseContains()で、レスポンス内容に『>ログイン</a>』が含まれていることなどもテストできます。

$this->viewVariable()によりControllerでset()した値が取れるので、正しく値がセットされているか等がテストできます。


表示がエラーになることのテスト

無効なパラメータや不正なアクセスの時に例外を投げる処理がある場合、それをテストします。


tests/TestCase/Controller/ArticlesControllerTest.php

public function testViewInvalid()

{
$this->get('/articles/view/hoge');
$this->assertResponseError();

// または以下でも可
$this->setExpectedException('Cake\Network\Exception\NotFoundException');
$this->get('/articles/view/hoge');
}


4xx(NotFound等)のレスポンスをテストする$this->assertResponseError()でエラーになることをテストします。

また、期待する例外(というのも変だけど)をsetExpectedException()で指定してget()などの前に書けば、特定のExceptionが発生していることをテストすることができます。


データを登録するテスト

フォームに何かを入力してDBに保存できることをテストします。


tests/TestCase/Controller/ArticlesControllerTest.php

public $fixtures = [

'app.articles',
]

private $__initialCount = null;

public function setUp()
{
parent::setUp();
$this->articles = TableRegistry::get('Articles');
$this->__initialCount = $this->articles->find()->count();
}

public function tearDown()
{
parent::tearDown();
unset($this->articles);
$this->__initialCount = null;
}

public function testAddPost()
{
$data = [
'title' => 'TEST title',
'start_date' => [
'year' => '2016',
'month' => '03',
'day' => '24',
]
];
$this->post('/articles/add', $data);
$this->assertRedirect(['action' => 'index']);
$this->assertEquals($this->__initialCount + 1, $this->articles->find()->count());
}


$dataの内容をPOSTし、indexにリダイレクトされることをassertRedirect()でテストします。

またDBのレコードが1つ増えていることをテストします。


バリデーションエラーになることのテスト

同様に、データをPOSTした時にバリデーションに引っかかってDBに保存できないことをテストします。


tests/TestCase/Controller/ArticlesControllerTest.php

public function testAddPostError()

{
$data = [
'title' => ''
];
$this->post('/articles/add', $data);
$this->assertNoRedirect();
$this->assertNotEmpty($this->viewVariable('article')->errors());
$this->assertArrayHasKey('title', $this->viewVariable('article')->errors());
$this->assertEquals($this->__initialCount, $this->articles->find()->count());
}

$this->viewVariable()でテンプレートにアサインされた(Controllerで$this->set()された)変数が取れるので、バリデーションエラーがある場合にセットされているerrors()が空じゃないこと、titleにエラーがあること等をテストします。

リダイレクトがなく、DBにもレコードが増えていないことをテストします。


ログインが必要なページのテスト

ログイン認証が必要なページは、セッションにログインしていることにしたい人の情報を入れることでログイン済みとしてアクセスさせることができます。


tests/TestCase/Controller/ArticlesControllerTest.php

public function testMypage()

{
$this->session(['Auth' => [
'User' => [
'id' => 1,
'email' => 'test1@example.com',
'name' => '山田太郎',
...
]
]]);
$this->get('/mypage');
$this->assertResponseOk();
$this->assertResponseContains('山田太郎さんこんにちは');
}

Cookieも$this->cookie('name', 'value')でセットすることができます。


送信するリクエストを設定してテスト

headerや$this->request->env()で取得できるような値も$this->configRequest()で設定することができます。

$this->request->clientIp()を見てアクセス制限をしているようなアプリケーションもテストすることができます。


tests/TestCase/Controller/ArticlesControllerTest.php

public function testIpAccess()

{
$this->configRequest([
'headers' => ['CLIENT_IP' => '12.34.56.78'],
'environment' => ['REMOTE_ADDR' => '23.45.67.89']
]);
$this->get('/limitedpage');
$this->assertResponseOk();
}

headersに指定した値は、頭に『HTTP_』が付く値(上記例ならHTTP_CLIENT_IP)として設定されます。(Controller内の$this->request->env('HTTP_CLIENT_IP')で'12.34.56.78'が返るようになります。)