CakePHP4でログイン認証のテストを書こうとした時に、セッションが取得できなくてハマったのでメモ
やりたかったこと(失敗コード)
UsersController
public function login()
{
$this->request->allowMethod(['get', 'post']);
$result = $this->Authentication->getResult();
// 認証成功
if ($result->isValid()) {
$target = $this->Authentication->getLoginRedirect() ?? '/';
return $this->redirect($target);
}
// ログインできなかった場合
if ($this->request->is('post') && !$result->isValid()) {
$this->Flash->error('ログインIDかパスワードが間違っています');
}
}
UsersControllerTest
public function testLoginOk(): void
{
$this->enableCsrfToken(); // CSRFトークン生成
$this->post('/users/login', [
'username' => 'misato', // idが2のユーザー
'password' => 'misato',
]);
// セッションのユーザーidが2であることを確認
$this->assertSession(2, 'Auth.User.id');
}
}
テスト結果
セッションが見つからなくて、失敗する
There was 1 failure:
1) App\Test\TestCase\Controller\UsersControllerTest::testLoginOk
Failed asserting that 2 is in session path 'Auth.User.id'.
【改善案】 テストコードは$_SESSIONを使う
UsersControllerTest
public function testLoginOk(): void
{
$this->enableCsrfToken(); // CSRFトークン生成
$this->post('/users/login', [
'username' => 'misato',
'password' => 'misato',
]);
$this->assertEquals(2, $_SESSION['Auth']->id);
}
これなら、テスト通る!!
OK (1 test, 1 assertion)
【おまけ】PHPUnitはリクエストごとにセッションがリセットされる
PHPUnitは同じテストメソッド内でも、リクエストごとにセッションがリセットされる仕様のようです。
そのため、セッションを引き継ぎたいときは、明示的にセッションを引き継がせる必要があります。
具体的には以下のような感じです
UsersController
public function home()
{
$session = $this->getRequest()->getSession();
if (empty($session->read('works'))) {
$session->write('works', 'on');
} else {
$session->write('works', 'off');
}
}
UsersControllerTest
public function testHome(): void
{
$this->get('/');
$this->assertSession('on', 'works'); //ここは成功します。
$this->session($_SESSION); // セッションを引き継ぐ
$this->get('/');
$this->assertSession('off', 'works'); //セッションを引き継がないと、ここで失敗
}