はじめに
とても便利なモッキングフレームワークであるAspectMockの導入で地味にハマったので記録メモになります。
正直なところ、環境によるものが多いので他であまり参考にならないかなと思いつつ、今後導入することがある時や、導入に困っている方のヒントになれば、と思いメモ書き程度に書いていきます。
いろいろ試しすぎていて何を試したか全てを覚えているわけではないので、なぐり書きっぽい感じになってしまっているのはご容赦ください
そもそも、AspectMockとは
利用している人も多いと思いますが、AspectMockは非常にパワフルなモッキングフレームワークです。
以前の現場で使っていた時も、なんでもできるなという印象があったので、現在の現場でも使うことになった次第です。
https://github.com/Codeception/AspectMock
参考記事
AspectMockの導入
AspectMockを使うために、composerを使ってインストールします。
$ composer require --dev codeception/aspect-mock
ハマっていたところ
今回は、commonディレクトリにあるServiceクラスのテストを書きたく、呼び出しているModel側をモックにしてDBからデータを取らないようにして、色々なパターンのテストを書こうと思っていました。
ですが、AspectMockでテストダブルを書いているのに、指定したモック用のキャッシュディレクトリにファイルが作成されず、モック化しているModelがDBからデータを引いてきているようで、モックの作成がうまく行っていないようでした。
環境
- PHP v7.2.22
- Yii2 Framework v2.0.22
- codeception v3.0.2
- PHP Unit v8.2.4
- codeception/aspect-mock v3.1.0
app
|-- backend
| `-- tests
|-- common
| |-- codeception.yml
| |-- models
| |-- services
| `-- tests
| |-- _bootstrap.php
| |-- unit
| | |-- models
| | `-- services
| `-- unit.suite.yml
`-- frontend
`-- tests
1. bootstrap
公式(codeception/aspect-mock)にあるbootstrapの設定方法 や、その他色々な記事にあるようなbootstrapの書き方をしたのですが、どうも現環境ではうまく動かない様子。
includePathsに指定しているのに、テストダブルで指定しているクラスが中々モックが作成されず、$kernelのインスタンスに以下のように無理やり読み込ませてみましたが、これだとcommon配下のファイルが全てcacheDirで指定したキャッシュディレクトリに全コピーされるような挙動をされてしまい、あまりイケていませんでした。
$kernel->loadPhpFiles(__DIR__ . '/../../common');
そのため、 上記のようなloadPhpFilesやloadFileを使わない方針で、他の解決策を模索し始めました。。
最終的には、bootstrapは公式で説明されているような以下のような形となりました(一部割愛)
<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'test');
defined('YII_APP_BASE_PATH') or define('YII_APP_BASE_PATH', __DIR__ . '/../../');
require_once __DIR__ . '/../../vendor/autoload.php';
require_once __DIR__ . '/../../vendor/yiisoft/yii2/Yii.php';
$kernel = \AspectMock\Kernel::getInstance();
$kernel->init([
'appDir' => YII_APP_BASE_PATH,
'debug' => true,
'includePaths' => [
__DIR__ . '/../'
],
'excludePaths' => [__DIR__ . '/../tests'],
'cacheDir' => '/tmp/cache/AspectMock'
]);
// もしYii::setAlias等が必要であれば、必要な分だけこの_bootstrapに書く必要があります
2. php-parserのバージョンが古い
PHPアプリ側のメソッドで、nullableな指定をしているメソッドが、モックのキャッシュを作る時にパースエラーになってしまっている様子。
どうやら、 nikic/php-parserのバージョンが古いようなので、こいつをupdate。
(他のパッケージとの依存関係があったりするので、updateするのには要調査、、、調査してくれた同僚の @Yoika さんに感謝 )
3. composer.jsonにautoloadの記載がない
composer.jsonに、autoloadを追記する必要があった。
各クラスに書いていたnamespaceはディレクトリの構成名通りなので、以下のように記載。
"autoload": {
"psr-4": {
"common\\": "common",
"frontend\\": "frontend",
"backend\\": "backend"
}
}
上記を記載して、
$ composer dump-autoload
を実行。
このあとモックを使ったテストを書いているUnitTestを実行したら、無事cache配下に必要なファイルだけキャッシュファイルが作成され、モックから期待する結果が返ってきました
その他
一部割愛してしまいましたが、環境によるとは思いますが他にも細かいところとして、
-
_bootstrap.php
にrequire_once
で呼び出す必要のあるファイルがあった - AspectKernelで読み込むファイルで
Yii::getAlias()
を使用しているところがあり、Yii::setAlias()
を_bootstrap.php
に書く必要があった
みたいなところがありました。
おわりに
あまり記事を書かないので分かりにくかったり、読みにくい箇所が多くて申し訳ないですが、あくまでも記録用メモとして見ていただければ幸いです。
記事中には書きませんでしたが、現状のアプリでうまくいかない様子だったときに、別に新規ですぐに立ち上がるPHPのFrameworkを使ってみて、PHP Unit内でAspectMockがすぐに動くことが確認できたので、そことcomposer.json
の比較をしてみたり、bootstrap.php
のの比較をしてみたりしました。
(今回は、興味本位で以下を参考にLaravelでWebアプリを立ち上げて比較・検証してみました)