初めに
前回はこちらの記事でFunctionalテストについて紹介しました。今回はDBアクセスのあるAPIをFunctionalテストで実装していこうと思います。
functionalテストとは
Functionalテストとは機能単位のテストを行うための機能です。Laravelのfeatureテストのようなイメージだと思います。
詳しくは前回の記事をご参照ください。
DBアクセスを含めたFunctionalテストを書いてみる
前回の記事では固定値を返すだけの単純なAPIに対してFunctionalテストを作成しました。今回はDBアクセスを含めたControllerに対するFunctionalテストを作成してみようと思います。
こちらがテスト対象のクラスです。
<?php
namespace Neos\Welcome\Controller;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\Mvc\Controller\ActionController;
use Neos\Welcome\Domain\Model\Functional;
class FunctionalTestController extends ActionController
{
/**
* @Flow\Inject
* @var \Neos\Flow\Mvc\View\JsonView
*/
protected $view;
/**
* @Flow\Inject
* @var \Neos\Welcome\Domain\Repository\FunctionalRepository
*/
protected $functionalRepository;
/**
* @return void
*/
public function indexAction()
{
// DBからデータを取得
$result = $this->functionalRepository->findAll();
// 最初の1件をレスポンスに詰める
$first = $result->getFirst();
$this->view->assign('value', [
'id' => $first->getId(),
'functionName' => $first->getFunctionalName()
]);
}
}
1. テストケース作成
以下のようなテストケースを作成しました。
ポイントは後述します。
<?php
namespace Neos\Welcome\Tests\Functional\Controller;
use Neos\Flow\Tests\FunctionalTestCase;
use Neos\Welcome\Domain\Model\Functional;
use Psr\Http\Message\ServerRequestFactoryInterface;
use Neos\Welcome\Domain\Repository\FunctionalRepository;
class FunctionalTestControllerTest extends FunctionalTestCase
{
/**
* @var bool
*/
protected $testableHttpEnabled = true;
/**
* ★ポイント1
* @var boolean
*/
protected static $testablePersistenceEnabled = true;
/**
* @var \Neos\Welcome\Domain\Repository\FunctionalRepository
*/
protected $functionalRepository;
/**
* ★ポイント2
* Additional setup
*/
protected function setUp(): void
{
parent::setUp();
$this->functionalRepository = $this->objectManager->get(FunctionalRepository::class);
}
/**
* @test
*/
public function functionaltest()
{
// Arrange
// ★ポイント3
$testData = new Functional("testId", "testName");
$this->functionalRepository->add($testData);
$this->persistenceManager->persistAll();
// Act
$response = $this->browser->request('http://localhost:8081/Neos.Welcome/FunctionalTest/index');
$responseArray = json_decode($response->getBody()->getContents(), true);
// Assert
self::assertSame('testId', $responseArray['id']);
self::assertSame('testName', $responseArray['functionName']);
self::assertSame(200, $response->getStatusCode());
}
}
ポイント
- DB接続を行うテストでは
$testablePersistenceEnabled
をtrue
にする
/**
* @var boolean
*/
protected static $testablePersistenceEnabled = true;
- データ作成や検証で利用するRepositoryは
setup()
の中で値を入れる
/**
* @var \Neos\Welcome\Domain\Repository\FunctionalRepository
*/
protected $functionalRepository;
protected function setUp(): void
{
parent::setUp();
$this->functionalRepository = $this->objectManager->get(FunctionalRepository::class);
}
- テストケースの中でDBのデータを作成
-
persistAll()
を行うことで永続化できる
-
// Arrange
$testData = new Functional("testId", "testName");
$this->functionalRepository->add($testData);
$this->persistenceManager->persistAll();
2. Settings.yamlにDB接続設定を記載
設定ファイルにDB接続設定を記載します。テストはTestingコンテキストで実行されるため、ConfigtrationのTesting配下にSettings.yamlを作成し、そこに記載します。
Quickstart
├ Configuration/
├ Testing
| └ Settings.yaml(★)
└ Settings.yaml
MySQLを使用してテストを行いたかったので、以下のように記載しました。
dbnameをmy_database_for_test
としていますが、このDBをあらかじめ作成しておく必要があります。
マイグレーションはFunctionalTest内で実行してくれるため必要ありません。create database hoge
のみでOK。
Neos:
Flow:
persistence:
backendOptions:
driver: 'pdo_mysql'
charset: 'utf8mb4'
host: '127.0.0.1' # Docker service name
dbname: 'my_database_for_test' # Database name
user: 'root' # MySQL user
password: 'root' # MySQL password
port: '3306' # MySQL port
driverOptions:
1002: 'SET SESSION wait_timeout=5'
3. テスト実行
実行結果がこちらです。
テスト一つに対して4秒かかっているのは、マイグレーションやデータ作成/削除のせいですかね、複数テストがあった時にどうなるのかはまた今度検証しようと思います。
$ .\bin\phpunit -c .\Build\BuildEssentials\PhpUnit\FunctionalTests.xml .\Packages\Application\Neos.Welcome\Tests\Functional\Controller\FunctionalTestControllerTest.php --debug
PHPUnit 9.6.22 by Sebastian Bergmann and contributors.
Test 'Neos\Welcome\Tests\Functional\Controller\FunctionalTestControllerTest::functionaltest' started
Test 'Neos\Welcome\Tests\Functional\Controller\FunctionalTestControllerTest::functionaltest' ended
Time: 00:04.864, Memory: 92.00 MB
OK (1 test, 3 assertions)
終わりに
前回に引き続き、今回はFlowのFunctionalテストを試してみました。
DB接続のテストがサクッとつくれるのは開発が捗りますね。今回はControllerから実行していますが、FlowのFW自体のFunctionalテストでは、Repository自体にDBアクセスを含めたFunctionalテストを作成しており、UnitTestのような感覚で書けるのはいいなとおもいましたね。可能性を感じています。
ここまでご覧いただきありがとうございました!