3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Yii2でPHP Unitを書くのにAspectMockを導入してハマったところメモ

Last updated at Posted at 2020-07-16

はじめに

とても便利なモッキングフレームワークであるAspectMockの導入で地味にハマったので記録メモになります。
正直なところ、環境によるものが多いので他であまり参考にならないかなと思いつつ、今後導入することがある時や、導入に困っている方のヒントになれば、と思いメモ書き程度に書いていきます。

いろいろ試しすぎていて何を試したか全てを覚えているわけではないので、なぐり書きっぽい感じになってしまっているのはご容赦ください :pray:

そもそも、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は公式で説明されているような以下のような形となりました(一部割愛)

最終的な_bootstrap.php
<?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 さんに感謝 :pray:

3. composer.jsonにautoloadの記載がない

composer.jsonに、autoloadを追記する必要があった。
各クラスに書いていたnamespaceはディレクトリの構成名通りなので、以下のように記載。

composer.json
    "autoload": {
        "psr-4": {
            "common\\": "common",
            "frontend\\": "frontend",
            "backend\\": "backend"
        }
    }

上記を記載して、

$ composer dump-autoload

を実行。

このあとモックを使ったテストを書いているUnitTestを実行したら、無事cache配下に必要なファイルだけキャッシュファイルが作成され、モックから期待する結果が返ってきました :joy:

その他

一部割愛してしまいましたが、環境によるとは思いますが他にも細かいところとして、

  • _bootstrap.phprequire_once で呼び出す必要のあるファイルがあった
  • AspectKernelで読み込むファイルで Yii::getAlias() を使用しているところがあり、 Yii::setAlias()_bootstrap.php に書く必要があった

みたいなところがありました。

おわりに

あまり記事を書かないので分かりにくかったり、読みにくい箇所が多くて申し訳ないですが、あくまでも記録用メモとして見ていただければ幸いです。

記事中には書きませんでしたが、現状のアプリでうまくいかない様子だったときに、別に新規ですぐに立ち上がるPHPのFrameworkを使ってみて、PHP Unit内でAspectMockがすぐに動くことが確認できたので、そことcomposer.jsonの比較をしてみたり、bootstrap.phpのの比較をしてみたりしました。
(今回は、興味本位で以下を参考にLaravelでWebアプリを立ち上げて比較・検証してみました)

参考記事

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?