Node.js Advent Calendar 2014の10日目の記事として、node.jsのコマンドラインツールをpower-assertとcoffee-scriptによってテストする方法を紹介します。
はじめに
Power assertとはassertテスト失敗時の情報を分かりやすく表示できる機能のことで、nodeで利用できるライブラリとして@t_wadaさん作のpower-assertというものがあります。
東京Node学園祭2014にて@t_wadaさんのpower-assertの発表を聴き、アサーション戦争に終止符を打つ!という熱い思いに感銘を受け、自作のツールにも積極的にpower-assertを使いたいと思っています。
本記事ではnode.jsでの簡単なコマンドの実装とpower-assertを使ったテストをcoffee-scriptで書く方法について順を追って解説します。
事前準備
ツール作成の準備
始めにclitestディレクトリを作成し移動します
1 2 |
$ mkdir clitest && cd clitest |
package.jsonの作成
各種パッケージを利用するために、npm initコマンドを実行しpackage.jsonを作成します。
コマンド実行時の質問にはツールの情報を適当に入力していきます。
テスト用ツールなのでEnter連打で適当に入力してもかまいません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
$ npm init This utility will walk you through creating a package.json file. It only covers the most common items, and tries to guess sane defaults. See `npm help json` for definitive documentation on these fields and exactly what they do. Use `npm install <pkg> --save` afterwards to install a package and save it as a dependency in the package.json file. Press ^C at any time to quit. name: (clitest) version: (1.0.0) description: entry point: (index.js) test command: git repository: keywords: author: license: (ISC) About to write to /clitest/package.json: { "name": "clitest", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" } Is this ok? (yes) y |
ツール用のライブラリ作成とテスト
テスト対象として文字列「hello!」を返却するライブラリ hello.js を実装し、テストを行います。
hello.jsを実装
hello.js
1 2 3 4 5 6 |
function hello(){ return "hello!"; } module.exports = hello; |
1-3行目で文字列”hello!”を返却する関数helloを定義しています。
5行目はこのjsファイルがインポートされた場合に関数helloにアクセスできるようにするための記述です。
hello.jsをテストしてみる
テストに必要なパッケージをインストール
テスト用に、mocha, power-assert, espower-coffeeパッケージをインストールしていきます。
始めにテストフレームワークのmochaをグローバルにインストール
1 2 |
$ npm install -g mocha |
次に、power-assertとcoffee-scriptでテストを実行するために必要なespower-coffeeをインストール
1 2 |
$ npm install --save-dev power-assert espower-coffee |
テスト用のcoffee-scriptを書く
coffee-scriptでテストを書きtestディレクトリに保存します。
test/libtest.coffee
1 2 3 4 5 6 7 8 |
hello = require '../hello.js' assert = require 'power-assert' describe 'libtest', -> it 'hello.js should return hello!', -> assert hello() == "hello!" |
1行目で先ほど作成したhello.jsをライブラリとして読み込みます。
2行目でpower-assertパッケージを読み込み。
4行目、6行目はテスト内容の説明。
7行目がテスト本体で、読み込んだhelloライブラリのhello関数の実行結果と文字列”hello!”を比較しています。
mochaを使ってテストしてみる
coffee-scriptで書いたテストをそのまま実行するために
–require ‘espower-coffee/guess’ オプションをつけてmochaでテストを実行します。
1 2 3 4 5 6 7 8 9 |
$ mocha test/libtest.coffee --require 'espower-coffee/guess' libtest ✓ hello.js should return hello! 1 passing (5ms) |
テストが成功しました。
テストを失敗させてみる
試しにテストを失敗させてみましよう。
libtest.coffeeの7行目の”hello!”を”world!”に変更して再度テストを実行してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$ mocha test/libtest.coffee --require 'espower-coffee/guess' libtest 1) hello.js should return hello! 0 passing (13ms) 1 failing 1) libtest hello.js should return hello!: AssertionError: # /clitest/test/libtest.coffee:9 assert(hello() === "world!") | | | false "hello!" --- [string] "world!" +++ [string] hello() @@ -1,6 +1,6 @@ -world +hello ! |
hello関数の出力に”world!”を期待しているのに、”hello!”が返ってくるためテストが失敗し、上記のようにテストがなぜ失敗したのかが詳細に出力されます。power-assertすごい!
ライブラリを読み込んで動作するコマンドラインツールの実装
先ほど作成したhello.jsは単体では動作しないライブラリでしたが、これを読み込んで動作するコマンドを実装します。
index.js
1 2 3 4 |
var hello = require('./hello.js'); console.log(hello()); |
1行目でhello.jsをライブラリとして読み込み。
3行目でhello()関数の戻り値をコンソールに出力します。
このコマンドを実行するとコンソールに”hello!”と出力されるはずです。
コマンドを実行
1 2 3 |
$ node index.js hello! |
期待どおり”hello!”がシェルに出力されました。
コマンド出力をテストするためのcoffee-scriptを書く
コマンド出力のテストを作成し、ライブラリのテストと同様にtestディレクトリに保存します。
clitest.js
1 2 3 4 5 6 7 8 9 10 11 12 |
assert = require 'power-assert' exec = require('child_process').exec cmd = 'node index.js' describe 'clitest', -> it 'index.js should return Hello world!', (done) -> exec cmd, (error, stdout, stderr) -> assert.equal stdout, "hello!\n" done() |
1行目でpower-assertを読み込み。
2行目でテスト用にコマンドを実行するためのchild_process.execメソッドを読み込み。
4行目で実行するコマンドを定義。
6行目8行目はテスト内容の説明。
9行目でコマンドを実際に実行します。
また、テストスクリプト側ではコマンド実行の終了を待つ必要があるため、8行目と9行目でコールバックを記述しています。
10行目でコマンドの出力stdoutと文字列”hello!n”を比較しています。
(コンソール出力であるため末尾に改行文字が入ります※1)
index.jsをテストしてみる
1 2 3 4 5 6 7 8 9 |
$ mocha test/clitest.coffee --require 'espower-coffee/guess' clitest ✓ index.js should return Hello world! (57ms) 1 passing (63ms) |
テストが成功しました。
試しにテストを失敗させてみる
clitest.coffeeの10行目の”hello!”を”world!”に変更して再度テストしてみる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ mocha test/clitest.coffee --require 'espower-coffee/guess' clitest 1) index.js should return Hello world! 0 passing (72ms) 1 failing 1) clitest index.js should return Hello world!: Uncaught AssertionError: # /clitest/test/clitest.coffee:10 assert.equal(stdout, "world!\n") | "hello!\n" |
コマンドの出力に”world!n”を期待しているのに、”hello!n”が返ってくるためテストが失敗し、なぜ失敗したのかが詳細に出力されます。やっぱりpower-assertすごい!※2
gulpでテストを自動化する
タスクランナーのgulpを使ってpower-assertを使ったテストを自動化します
gulpと関連パッケージのインストール
gulpをグローバルにインストール
1 2 |
$ npm install -g gulp |
ローカル側gulpと関連パッケージをインストール
1 2 |
$ npm install --save-dev gulp gulp-mocha |
gulpfile.coffeeを作成
gulpfile.coffee
1 2 3 4 5 6 7 8 |
gulp = require 'gulp' mocha = require 'gulp-mocha' gulp.task 'mocha', -> require 'espower-coffee/guess' gulp.src './test/**/*.coffee' .pipe mocha() |
1行目と2行目でパッケージの読み込み。
4行目で自動テストのためのタスク”mocha”を定義。
5行目でcoffee-scriptでpower-assertするためのespower-coffee/guessを読み込み。
6行目7行目でtestディレクトリのcoffee-scriptを実行してテストを行う。
gulpでテストしてみる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ gulp mocha [01:14:29] Requiring external module coffee-script/register [01:14:29] Using gulpfile ~/clitest/gulpfile.coffee [01:14:29] Starting 'mocha'... clitest ✓ index.js should return Hello world! (56ms) libtest ✓ hello.js should return hello! 2 passing (59ms) |
libtest.coffeeとclitest.coffeeの両方のテストが実行されます。
試しにテストが失敗するようにテストスクリプトを修正してpower-assertのパワーを感じてみてください!
以降は、随時必要なテストを追加し、いつでもgulp mochaコマンドでテストを実施できます。
おわりに
node.jsで簡単なコマンドを実装し、ライブラリの関数出力およびコマンドライン出力を
power-assertとcoffee-scriptにてテストする方法を紹介しました。
(サンプルコードはknjcode/clitestに置いてあります)
さらなる発展として、複数行のコマンド出力のテストや配列比較のテスト方法、
さらにはTravis CIと連携した自動テスト手法等を紹介したいと考えていますが、
また、別途記事にしたいと思います。
明日のNode.js Advent Calendarはchocopie116さんです。
補足
※1.コマンド出力の改行コードは環境により異なる場合があります。
※2.大事なことなので2回言いました。
また、東京Node学園祭にてt_wadaさんにpower-assertのコードを個別解説頂いた際、
鮮やかなEmacs操作に対して「それVimですか?」と聞いてしまったのは私です。大変失礼致しました。
参考
power-assertの使い方 Node.js編
Coffee-scriptでpower-assertを使ったテストを書く
twada / gulpfile.js
power-assert / mechanism and philosophy