Webpackモジュールのプライベート関数をユニットテストしたい

レガシーなJavaScriptソースをWebpackでビルドできるようにモジュールに切り分けてテストを書くことをしている(わりとヒマなので)。

jsモジュール内の機能をプライベート関数に分割して書く場合に、そのプライベート関数部分の単体テストを書きたい場合があると思うんだけど、それをどうやればいいのかわからなくていろいろ調べた。

unit testing - How to access and test an internal (non-exports) function in a node.js module? - Stack Overflow

こういう話で、ここではrewireを使えという事になってるんだけど、これはうまくいかなかった。rewire-webpackというのもあるんだけど、これもだめだった。

でうまくいったのは、exports-loaderでプライベート関数を指定してエクスポートする方法で、

1
2
3
4
5
6
7
8
9
10
11
function privateFunc() {
return "private";
}
function exportFunc() {
return "export";
}
module.exports = exportFunc;

こういうモジュールのテストを

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
describe('test', function() {
it('モジュールのテスト', function() {
var exportFunc = require('export-module.js');
expects(exportFunc()).toBe('export');
});
it('プライベート関数のテスト', function() {
var privateFunc = require("exports?privateFunc!./export-module.js");
expects(privateFunc).toBe('private');
});
});

こんな感じにしたらうまくいった。


AspectMockを使うクラスでyieldを使ってるとき

AspectMockでモッキングするクラス(に依存するクラス)でyieldを使ってると、AspectMockが注入するコードがreturnで値を返そうとするためエラーになる。

PHP Fatal error:  Generators cannot return values using "return" in /...

とりあえずキャッシュコードのreturnをyieldに変えて動かしてたけど、もうissueになっててdev-masterでは解消されているっぽい。

Generators result in fatal error · Issue #50 · Codeception/AspectMock

Composerでdev-masterのモジュールをインストールする(”minimum-stability”: “dev”にしてもいいけどこれだと全モジュールのdev-masterが入る)

"require-dev": {
   ...
   "codeception/aspect-mock": "dev-master"
   ...
}

上記修正は返り値のキーワードをPHPDOCの@returnで判別するものなので、AspectMockのキャッシュを消して、yieldを使ってるメソッドのPHPDOCの@returnに \Generator を書く(Generatorだけだとだめだった)

/**
 * @param $name
 * @return \Generator
 */
public function generatorMethod($name)

これで動いた。AspectMock黒魔術感あってハマると苦しい…。