紙の裏のメモ

崖の上のポニョみたいなイントネーションです。坂の上の雲みたいな(ry

sinonでNodeのprocess.envにbool値を定義してテスト

javascriptのテストを書く時に、環境変数であるprocess.envに値をセットしてテストした時があると思います。 そんな時、process.env.HOGE= 'HOGE'; のように文字列を代入する時には問題は起こらないのですが、process.env.FUGA = trueというように bool値を代入しようとすると問題が発生します。

それについて少しメモを残します。

何が起こるのか

Node.jsのドキュメントには以下のように書いてあります。

Assigning a property on process.env will implicitly convert the value to a string. This behavior is deprecated. Future versions of Node.js may throw an error when the value is not a string, number, or boolean.

https://nodejs.org/api/process.html#process_process_env

つまりはprocess.envとして定義した値はstringに変換される。ということです。 (This behavior is deprecated.... 以降の文から将来的にはnumberやbooleanを割り当てた時にどうなるのかは読み取れませんでした。)

このようなコードがあった時の挙動について少し説明を加えてみます。

if (process.env.HOGE) {
  console.log('hoge')
}

このようなコードがあった時、test上で process.env.HOGE = false と定義したとしても process.env.HOGEの値は 'false' という文字列となり、process.env.HOGEの値は文字として存在することになります。 したがって、本来読み込まれてほしくないconsole.log('hoge') が読み込まれてしまう。という挙動になります。

開発環境での定義

注意する必要があることは、開発環境でもprocess.envの値が必ずしも文字列として定義されているわけではないということです。

僕はwebpackをよく使うのでwebpackでの説明に限定させてもらうのですが、webpackで環境変数を定義する時にはbooleanとして定義できてしまいます。 webpackでprocess.envの値をセットする時にはおそらくDefinePluginを利用することが多いかと思います。

こちらのプラグインでprocess.envを定義した際には、stringとしてもbooleanとしても定義できてしまいます。 したがって process.evn.HOGEの値は'true'ではなくtrue と定義されている可能性もあるのです。

個人的には、実際コードを書く時も、

if (process.env.HOGE === 'true') {
  console.log('hoge')
}

のように書くよりも

if (process.env.HOGE) {
  console.log('hoge')
}

というように書いてしまいたいです。なのでtestでも booleanとして定義できるようにするのが、僕にとっては最適でした。

sinonを利用してprocess.envを定義

このような時に利用できるのがsinonです

sinonでは、stubとして値を定義することができ、それはprocess.envにも適用できます。 詳しい使い方はドキュメントを見ていただくといいかと思います。

例えば、以下のようにすることで、booleanのHOGEをprocess.envにセットすることができます。

import sinon from 'sinon';

const sandbox = sinon.createSandbox();
sandbox.stub(process, 'env').value({ HOGE: true });

これで process.envにbool値を定義した上でテストを行うことが可能になります。