LoginSignup
2

More than 3 years have passed since last update.

Node.jsでprivateメソッドをテスト方法を検討

Posted at

概要

Node.jsに限らず各言語でpriateメソッドをテストする際、程度の差はありますが工夫が必要にあります。
今回はNode.jsでpriateメソッドをテストするまでに時間を要したので、メモとして残しておきます。

読者対象

  • priateメソッドをテストしたいけど、面倒なので放置した方

不採用になった案

結論は自前でやることになったのですが、パッケージやコードがないかなと思ってググりました。
その中で採用候補になったものをあげておきます。

requireで細工をする

Nodeでプライベートな(exportsされてない)メソッドのテスト
http://nazomikan.hateblo.jp/entry/2013/04/10/032410
vm.runInThisContext()にする場合の補足
https://stackoverflow.com/questions/20899863/the-module-property-is-undefined-when-using-vm-runinthiscontext

これはrequireを通すとexportされてないものがロードできないため、自前でrequireを用意するやり方です。
似たような感じにして作ってみましたが、私はうまく行きませんでした。
やり方が悪かったのか、記事が古くvm.runInNewContext()の仕様が変わったのかは不明です。
テストコードが比較的スマートなので採用する予定でした。
しかし、一部キャッシュされたモジュールを使いまわす前提の箇所があり、contextが別になるとそこの動作への懸念が出たので不採用になりました。

rewireを導入

rewireパッケージを使うことも検討しました。
普段の書き方と変わるのが少しマイナス。
あまり好まないので、さらに検討を進めて自前になりました。

後で以下を見て、これでも悪くないかなと思ったのは内緒です。
const test123 = require('./index').__get__('test123');
https://www.grzegorowski.com/jest-tests-with-rewire-plugin/

実践

通常と同じ動作をしてほしいし、複雑なことはやりたくない。
とにかくシンプルがいい。ただ、テストの時だけpublicにしたいだけなのに…条件で切り替えればいいだけじゃないか:hugging:
思いついたら後は作るだけ。

test.js

const firebaseUtil = require('./firebase/util.js');

test('call private method', () => {
    firebaseUtil.privateMethod();
})

firebaseのutilモジュールにあるprivateメソッドをコールするテストを想定します。
privateMethodはexportしていないので、このままでは実行エラーになります。

firebase/util.js

const { getPrivateMethodsInTest } = require('../utils/testHelper'); // add code

const publicMethod = () => console.log('this is public');
const privateMethod = () => console.log('this is private');

module.exports = {
    publicMethod,
    ...getPrivateMethodsInTest({ privateMethod }) // add code
};

util.jsではpublicMethod()とprivateMethod()があり、publicMethodは通常通りexportしており、privateの方はgetPrivateMethodsInTest()というメソッドを挟んでいます。
getPrivateMethodsInTest()がカギになります。

utils/testHelper.js

const getPrivateMethodsInTest = 
    (methods) => process.env.NODE_ENV === 'test' ? methods : {};

module.exports = { getPrivateMethodsInTest };

jestの場合、テスト実行時にprocess.env.NODE_ENVに'test'が入るため、それによって渡されたメソッドをそのまま返すか、空のオブジェクトを返すか切り替えているだけのシンプルなものです。
この戻り値を呼び出し元で展開することで、テスト時にはprivateメソッドがexportされ、それ以外の場合にはpublicメソッドのみが展開されるようになります。
この案のメリットはテスト時は通常のpublicメソッドなので、トラブルの心配がないというところです。

シンプルにまとまっていると思いますが、対象となるソースが多くなってくると煩わしく思えるかもしれません。
その場合はrewireの採用を検討したほうがいいかもしれません。

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
2