読者です 読者をやめる 読者になる 読者になる

console.lealog();

@leader22のWeb系に関する勉強めもブログですのだ

0からはじめるpower-assert

JavaScript Node.js

テスト書いてないとかお前そ(ry

すみません、言ってみたかっただけです。

そして本記事は、巷で話題のAdvent Calendarとも何の関係もありません。
来年こそは書いてみたい!

そもそも

こんなたいそうなタイトルの記事ですが、
書いてる人がそもそもテストに関してぺーぺーなので、なんか変なコト言ってたら教えてください。

まず、根本的に勘違いしてたことがあるので、まずそれを記しておきます。
※今思えば個人の勝手な勘違いです。

巷で話題のpower-assertですが、これだけ使えばもうテスト全ておっけー!ってものではないです。
そして、サクッと入れてサクッと使えるってものでもないです。

よーわからんけどテスト書いた方が良いって最近よく聞くし、
power-assertってのがとりあえずイケてるらしいから、それ使ってテストデビューしてみようかな・・って人。

それなりに前提知識がないと辛いです、もとい、辛かったです。
ただ、そんな人でもなんとか使えるようにってのが本記事の趣旨でございます。

決してpower-assertというツールが難しいのではなくて、
そもそもツールを使うための予備知識がないと、ありがたみがわからないまま挫折しちゃうかも?ってことです。

最低限、テストって何かとかどんな風にやるかをなんとなーく知ってれば、なんとかなります。

というわけで予備知識

power-assertってなんぞ

ご存知テスト界の神様と謳われる@t_wadaさん作の、JavaScript版 Power Assert ライブラリです。
ありがたやありがたや。

twada/power-assert

READMEはひと通り目を通したいところですが、割と長いので、Descriptionから2点だけ。

provides descriptive assertion messages through standard assert interface.

"Standard assert interface" ってのが重要なポイント。
Node.jsにはAssertってAPIがあって、それをより強化したものが提供されます。

Assert Node.js v0.10.33 Manual & Documentation

assert自体は改めて後述しますが、まずはコレの存在と、使い方を知るべし。

to use power-assert, you need to transform your test code for power-assert output.

というように、power-assertを使って書いたテストコードは、そのままでは実行できません。

と、勝手に思ってたのですが、

いやはやすみません!

なにはともあれ、
これはpower-assertがテスト失敗時に詳細なメッセージを表示するために必要な過程で、
何かを得るためには、それと同等の代価が必要になるのです。


詳しくは以下の資料を参照ですが、読み飛ばしてもだいじょぶです。

テスト用ライブラリ power-assert

Power Assertって既存の概念やったんねー。

mochaってなんぞ

いきなり何の話やねんって感じですが、大事ですコレ。
個人的にはコレが一番最初に知っておくべき知識でした。

jsのテストのサンプルを探すと、だいたいしれっとmochaが使われてます。
何の前置きもなく、さぞテスト書くならmochaだろうみたいな空気です。

あの頃は、そもそもmochaってなんやねん!ってなってました。
power-assertの前にそもそも知っとけって感じですね。

0からはじめるmocha

mochaはいわゆるテストランナーってやつです。
このmochaのお作法にそって、テストコードを書いてくと幸せになれるよってやつです。

究極的にはこんなの使わずとも、ベタにテストケースをif文とconsole.logで延々と書けば良いですが、
そこはまぁ先人の偉業に身を任せましょう。

アウトプットもわかりやすくなるし、テストケースも体系だって書けます。

// test.js
'use strict';

var assert = require('assert'); // さっきのAssert奴

describe('ここは見出し', function() {
  it('ここがテスト項目の名前', function() {
    assert(1 + 1, 2); // これがテストしたい項目
  });
  it('ここがテスト項目の名前そのに', function() {
    assert.notDeepEqual({ a: 1 }, { a: 1, b: 2 }); // これがテストしたい項目そのに
  });
});

という感じです。
ほらわかりやすい!

  • describe
  • it

とりあえずこの2つさえ知ってればテストは書けます。
ってどっかの偉人が言ってました。

テストフレームワーク mocha - hokaccha.hamalog v2

すーぱーありがたい記事があったので、こちらも参考に。

Assert

さて、全体像の書き方はわかったところで、細かいテストコードについて。

さっき出てきたNodeのAssertには、以下のメソッドがあります。
これを使い分けていくことになります。

  • assert.fail(actual, expected, message, operator)
  • assert(value, message), assert.ok(value, [message])
  • assert.equal(actual, expected, [message])
  • assert.notEqual(actual, expected, [message])
  • assert.deepEqual(actual, expected, [message])
  • assert.notDeepEqual(actual, expected, [message])
  • assert.strictEqual(actual, expected, [message])
  • assert.notStrictEqual(actual, expected, [message])
  • assert.throws(block, [error], [message])
  • assert.doesNotThrow(block, [message])
  • assert.ifError(value)

・・・( ゚д゚)多い。

もちろん必要に応じて使い分ければよいのですが、最初は何のことやらです。
ちゃんと使い分けた方がいいのか・・そもそもコレなんや・・テスト辛い・・やめとこかな・・。

ってなりそうなそこのあなた!
ここで満を持して登場するのがpower-assertです。

power-assert!

アサーションメソッドはいっぱいあるけど、迷ったらとりあえずassertで書いとけ!
コケたら理由はちゃんと教えたるから!

的な気概で、jsテスト道への第一歩を後押ししてくれるのがpower-assertだと私は思いました。

では、いよいよ詳細な使い方です。

gulp

おそらくコレが一番簡単で実用的だと思ったので、今回はgulpを使います。

最終的に、

gulp test

ってすると、テスト実行してくれるようにしたいですね。

インストール
npm install --save-dev gulp gulp-espower gulp-mocha power-assert

必要に応じてグローバルなgulpも。

タスク書く
// gulpfile.js
'use strict';

var gulp    = require('gulp');
var espower = require('gulp-espower');
var mocha   = require('gulp-mocha');

gulp.task('test:make', function() {
    gulp.src(['test/*.js'])
        .pipe(espower())
        .pipe(gulp.dest('test/espowered'));
});

gulp.task('test:exec', function() {
    gulp.src(['test/espowered/*.js'])
        .pipe(mocha());
});

// or 中間ファイルが不要であればコレで実行だけできる
gulp.task('test', function() {
    gulp.src(['test/*.js'])
        .pipe(espower())
        .pipe(mocha());
});

おどろきの短さ!

最初のほうにpower-assertを使って書いたテストコードは、そのままでは実行できないと書きました。
その変換処理をやってるのがespowerです。

この例でいうところのtest:makeの処理ですね。

モジュールを書く

詳しくは割愛しますが、テストしたい対象であるモジュールを書きます。
てか書いたからテストしようって思ったのでは!

注意があるとすれば、Nodeでテストする以上、ちゃんとmodule.exportsしておくくらい?

テスト書く

さっきのmochaのとこで紹介したのが、ほぼそのまま使えます。

// test.js
'use strict';
var assert = require('power-assert'); // <- assert を power-assertにしただけ

describe('サンプルテスト', function() {
    it('テスト項目: 1', function() {
        assert(1 + 1, 2);
    });
    it('テスト項目: 2', function() {
        assert.notDeepEqual({ a: 1 }, { a: 1, b: 2 });
    });
    it('テスト項目: 3', function() {
        var zero = 0, two = 2;
        var arr = [1, 2, 3];
        assert(arr.indexOf(zero) === two);
    });
});

// ...

楽ちんですねー。

あとは実行するだけ!

テスト実行

このサンプルだと、

gulp test:make && gulp test:exec

ですが、package.jsonに定義しちゃえば、

npm test

ってできますね。

3つ目のテストはわざと落ちるようにしてあるので、power-assertの親切さ具合を味わいましょう。
数多の解説記事で見かけた親切丁寧なメッセージが見えてるはずです。

これで晴れてあのAAに怯える必要はなくなりました!

さいごに

というわけでざっくりまとめると、

  • power-assertだけではテストは書けない
  • いまテスト書くならmochaを知っとくと良さげ
  • assertメソッドの使い分けに気を病むくらいなら、power-assertでassertすべし
  • なによりテストは書いてみることに意義がある!

今回のサンプルは、以下のリポジトリに置いてあります。
必要ならどうぞ。

leader22/hello-power-assert

いま知りたいこと

とりあえずテストという存在に対してはある程度前向きになれましたが、
次なる壁はすぐに立ちはだかるもので・・・。

  • テストコードからのrequireのパスのうまいやり方
  • テストケースの考え方(粒度など)とは
  • テストコードそれ自体の良い書き方とは
  • ブラウザのDOMまわりのテスト
  • てかUIのテストとは

こういうのが最近気になるトピックです。

特にDOMまわりは気になるところで、世間にはSeleniumとかKarmaとかPhantomJSとかなんやか色々あるようですが、
結局のところAndroidのよくわからん挙動とか拾えんし、アニメーションとかわからんしなーとか考えてしまいます。

とりあえず、UIが絡まない + I/Oが疎なロジック関連だけは積極的にテスト書いてこうと思ってる今日このごろです。