複数のコンポーネントが連動するアプリケーションのテストを書くとき、「どこまでを本物を使ってどこからモックするか」みたいな話は開発の現場のいたるところであると思います。 「要はバランス」だったり「答えは現場の数だけあ」ったり*1。
外部コマンドの実行をスタブしたい
ある外部コマンドの実行を含むコードのテストを書こうとしたのですが、
- 外部コマンドの用意自体が意外に面倒くさいタイプのものだった
- バイナリの存在チェックだったり実行だったり、コードの各所でその外部コマンドに関係するコードがあった
- 一方で簡単な標準出力やステータスコードを返せばテストとしては成り立ちそうだった
という状況で、コード内に外部コマンドの実行をモックできる仕組みを作るにはちょっとコストが高いなと感じて、「適当なスタブ用バイナリを用意すればいいのでは」と考え作ってみました。
stubin
stubinは任意のコマンドのスタブの役割をするためだけに生まれてきたバイナリです。普通に実行すると何も出力せずExist status 0で終了します。
stubinに挙動を渡す方法は環境変数です。
通常は環境変数 STUBIN_STDOUT にstubin実行時の標準出力の内容、 STUBIN_STDERR に標準エラーの内容を、STUBIN_STATUS にExist statusを事前にセットしておくと実行時に環境変数に沿った動きをします。
$ export STUBIN_STDOUT="Hello, stubin! " $ stubin Hello, stubin! $
スタブのための機能
上記で「通常は」と書いたのは、stubinは少しアドバンストな使い方ができるからです。
バイナリをリネームすると対応する環境変数も変わる
スタブしたいバイナリは1つとは限りません。stubinはそのための機能を持っています。
stubin というバイナリを例えば fakecmd にリネームすると、バイナリに対応する環境変数が FAKECMD_STDOUT FAKECMD_STDERR FAKECMD_STATUS に変わります。
このようにstubinをコピーしてリネームするだけで必要な数だけスタブコマンドを増やすことができます。
条件を指定して出力内容を変えることができる
引数が全て格納されているargs という変数をつかって条件を指定することで条件に合致した場合の出力も環境変数で設定できます。
具体的には [バイナリ名]_EXPECT_COND という環境変数に条件記載して、[バイナリ名]_EXPECT_STDOUT、[バイナリ名]_EXPECT_STDERR、[バイナリ名]_EXPECT_STATUS に条件を合致した時の出力内容やExit statusを指定しておけばその動きをします。
複数の条件と出力を設置したいときはサフィックスを追加することで条件と出力の対応を増やすことができます。
次の例では _HELP と _TEST サフィックスをつけています。
$ export STUBIN_EXPECT_COND_HELP="'-h' in args" $ export STUBIN_EXPECT_STDOUT_HELP="Usage: stubin [-h] " $ export STUBIN_EXPECT_COND_TEST="'test' in args" $ export STUBIN_EXPECT_STDOUT_TEST="This is test. " $ stubin $ stubin -h Usage: stubin [-h] $ stubin test This is test.
スタブの役割をするためだけに生まれてきたバイナリ
スタブ用なので自分のバージョン表示をすることもなく環境変数で挙動を変えるだけのバイナリstubin。作っていてちょっと寂しい気持ちになりました。
もし必要になることがあれば思い出してあげてください。
*1:ちなみに私は積極的にミディアムテストにしてしまう派です。