この記事は、初めてJavaScriptのテスト環境を作ってみたおじさんによる、これからJavaScriptのテストを書いていきたいけど、登場人物が多すぎてなにやらめんどくさそうと思っている方に向けた記事兼備忘録です。
初めてのJavaScriptテスト環境構築で一応公式ドキュメントに目を通したけど英語の意味をちゃんと読み取れておらず、ツールやライブラリの理解や使い方が間違っている場合がありますのでアドバイスいただけると幸いです。
各テストツールやライブラリの紹介
JavaScriptのテスト環境を構築するときの一つ目の壁がツールやライブラリがたくさん出てきて、どれを使っていいかわからない/それぞれの役割がわからないことだと思う。
なので、まずはJavaScriptのテスト環境についてググったときに出てくる最近使われてそうな各ツールやライブラリの役割をすごく雑に紹介します。
テストフレームワーク
以下で紹介するフレームワークはどれも見た目がRSpecっぽい。触ったことがあれば雰囲気は簡単につかめるはず。
mocha
Mocha - the fun, simple, flexible JavaScript test framework
- クライアントサイドとサーバサイドの両方で動作する
- アサーションやmock/stub機能は持っていないので他のライブラリと組わせて使う
RSpecっぽいBDDスタイルのほかにも, TDD, Exports, QUnit, Require-styleの中から好きなインターフェイスを選択して書ける。テスト結果の出力もかなり柔軟に指定できる感じで猫が走ったりする。ドキュメントを読む限りだと非同期処理のテストも簡単に書けそう。
describe('#indexOf()', function () {
it('should return -1 when the value is not present', function () {
assert.equal(-1, [1,2,3].indexOf(5)); // アサーションは自由に選択化
assert.equal(-1, [1,2,3].indexOf(2));
});
});
Jasmine
Jasmine: Behavior-Driven JavaScript
- サーバサイドはjasmine-nodeを使う
- mockやアサーションのライブラリが備わっている
describe("A suite", function() {
it("contains spec with an expectation", function() {
expect(true).toBe(true);
});
});
jest
Jest | Painless JavaScript Unit Testing
- テストフレームワーク
- Facebookが作ったJasmineの拡張テストフレームワーク
- mockやアサーションのライブラリが備わっている
Jasmineとの違いとして読み込むコードは全てMockとして扱われ、テスト対象コードをMockから明示的に除外して使うのが特徴。
jest.dontMock('../sum');
describe('sum', function() {
it('adds 1 + 2 to equal 3', function() {
var sum = require('../sum');
expect(sum(1, 2)).toBe(3);
});
});
アサーション
アサーションライブラリを自由に選択できるmochaで使う
power-assert
アサーションライブラリとして説明されること多いが、APIはNode.jsの単純なAssert API。power-assertはテストが失敗したときの出力結果を拡張したもの。テストが失敗したときの情報をたっぷり出力してくれるため、他ライブラリのようにたくさんのアサーションAPIを使い分ける必要がない。
以下のスライドと記事が詳しい
5minで分かるpower-assert
power-assertの使い方 Node.js編 | Web Scratch
power-assertでJavaScriptのテストをする ブラウザ編 | Web Scratch
chai
should/expect/assertの好きな記法を選択でき、power-assertとは逆にAPIがたくさんある。
mock/stub
アサーションライブラリと同様に自由に選択できるmochaで使う
mock/stubについての理解は以下の記事の解説がわかりやすいかと思います
使えるRSpec入門・その3「ゼロからわかるモック(mock)を使ったテストの書き方」 - Qiita
Sinon
テストランナー
karma
Karma - Spectacular Test Runner for Javascript
ブラウザ上でテストを走らせるためのツール。mocha等のテストフレームワークとは提供されているプラグインを使って連携する。
どのフレームワークもテストランナーを使わなくてもテストを実行できるが、Karmaを使えば複数のブラウザやデバイス上でのテストが簡単にできる。
またリモートでの実行やテストカバレッジの計測もできるらしい。
ここまでのまとめ
テストフレームワークを使ってテストを書いて、Karmaで走らせる。テストフレームワークにmochaを採用する場合は、アサーションやmockライブラリを別途選択する。
これにプラスしてmodule化されたJavaScriptやbabelをブラウザで使えるようにwebpackやbrowselify等を組み込むことになるかと思います。
次に実際にテスト環境を作って、簡単なテストを実行していきます。
今回の構築するテスト環境の構成
- Mocha + power-assert + Karma + babel + webpack
power-assertを使ってみたかったのでフレームワークはmochaを採用。Karmaのプリプロセッサには慣れているwebpackを使う。
ゴール
Mochaで書いたコードをwebpackでpower-assert用のコードに変換してkarmaを使ってブラウザ上でテストを走らせる。またbabel(babel-plugin-espower)を使ってテストとテスト対象になる本体のコードをES2015を使えるようにする。
今回はwebpackとbabelを使ったES2015環境の構築の説明は省きます。
以下で作っていくテスト環境のコード
cotto89/sample_js_test: Mocha + power-assert + Karma + babel + webpackを使ったJavaScriptテスト環境のサンプル
ベースになる環境構築
webpack + babelを用いた環境を用意。今回は以下のようなディレクトリ構成で進めていく。
.
├── index.html
├── package.json
├── src
│ └── index.js
├── test
│ └── sample_test.js
└── webpack.config.js
Mochaを導入
npm i -g mocha
package.jsonにtaskを登録
"scripts": {
"test": "mocha"
},
// mocha公式ドキュメントより拝借
var assert = require('assert');
describe('Array', function() {
describe('#indexOf()', function () {
it('should return -1 when the value is not present', function () {
assert.equal(-1, [1,2,3].indexOf(5));
assert.equal(-1, [1,2,3].indexOf(1)); // ここが失敗する
});
});
});
とりあえず安心するために、テストを走らせ期待通りテストが実行されることを確認する
npm test
Karmaを導入
karma-cli
をインストールしてkarma init
。対話形式で使うブラウザやテストフレームワーク、testまでのpath等について聞かれるので適当なものを選択するとkarma.conf.jsが生成される。その際に選択した環境に必要なmoduleは自動でnpmにinstallされる。
npm i -g karma-cli
さらにpreprocessorにwebpackを使うためにkarma-webpack
をインストール
npm i -D karma-webpack
preprocessorはkarmaの前処理で、webpackでブラウザで動くコードに変換されてKarmaにコードが渡る
webpack/karma-webpack: Use webpack with karma.
とりあえず安心するために、Karmaを走らせて期待通りに動作することを確認する
...
preprocessors: {
// add webpack as preprocessor
'test/*_test.js': ['webpack'],
'test/**/*_test.js': ['webpack']
},
...
"scripts": {
"test": "karma start"
},
npm test
これでmochaで書いたテストがwebpack経由でkarmaに渡されてtestがブラウザ上で実行されることが確認できた
power-assertを導入
power-assertとその他に必要なmoduleをインストール
power-assertとテストコードもES2015で記述できるようにbabel-plugin-espower
を導入する
webpack-espower-loader does not work with babel-loader!
webpack-espower-loader does not work with babel-loader due to the change of transpiled code since babel 5.0. Please use babel-plugin-espower with babel-loader.
power-assert-js/webpack-espower-loader: Power Assert instrumentor module for webpack
とのことなのでpower-assert + babel + webpackを使う場合は、webpack-espower-loaderは使わずにbabel-plugin-espowerを使う
またCannot find module Error · Issue #2 · power-assert-js/webpack-espower-loaderの理由でjson-loaderもインストールする
npm i -D power-assert babel-plugin-espower json-loader
karma.conf.jsを編集
プリプロセッサで利用するwebpackをsetup
...
webpack: {
devtool: 'inline-source-map',
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015'],
plugins: ['babel-plugin-espower']
}
},
{
test: /\.json$/,
loader: 'json'
}
]
}
},
...
動作確認
テストを含めてES2015で書いたコードを書いて動くことを確認。
適当なテスト対象となるコードを用意
export default class Cat {
constructor(name) {
this.name = name;
}
greet() {
return `Nyaaaan! I am ${this.name}`
}
}
ES2015でテストを書いてみる
import assert from 'power-assert'
import Cat from '../src/cat'
describe('Cat', () => {
var tama;
beforeEach(() => {
tama = new Cat('tama')
});
describe("greet()", () => {
it("挨拶をする", () => {
assert.equal(tama.greet(), 'Nyaaaan! I am neko');
});
});
});
問題なくテストが実行され、power-assertによる出力を確認することができた
まとめ
細かいことはわからないけどテスト環境を作ってとりあえず動くところまではできた。一度手を動かして各ツールやライブラリの役割を把握しておくことで、他の構成で組む場合でも全体像を把握できているのでわりと楽に組めるのではと思う。
あとは各ツールやライブラリのドキュメントを読んで細かいオプションを指定するなりどんどん使いやすいようにカスタマイズしていく。
とりあえず動くとこまではきたが、webpack + babel + power-assertあたりの設定にこれでいいのか不安があるので間違っていたらアドバイスください。
cotto89/sample_js_test: Mocha + power-assert + Karma + babel + webpackを使ったJavaScriptテスト環境のサンプル