2016-8-8
※webpack単体の記事を書きました。よろしければこちらもどうぞ step by stepで始めるwebpack
2016-5-16
※karma単体の記事を書きました。よろしければこちらもどうぞ step by stepで始めるKarma
本記事は画面のJavaScriptのテストとかまったくやったことない方
Mocha?webpack?karma?それぞれの解説記事はよく見るけど全体像がよくわからんという方向けです。(数日前の自分です)
全体を通して導入の流れを解説した記事があると全体像が理解しやすいのではと思い書いてみました。
前提
Nodejs,npm,chromeが導入済みであること
流れ
Step | 表題 | 目的 |
---|---|---|
Step 0 | テスト対象アプリケーションを作成 | |
Step 1 | ライブラリを使わないでテスト | ブラウザのconsole機能でテストを行う |
Step 2 | Mochaを導入 | テスト結果をリッチにする |
Step 3 | Nodejsでテストを実行 | ブラウザの世界からNodejsの世界にテストを持って行き、後続のStepへつなげる |
Step 4 | webpackを導入 | ブラウザ上でモジュールの読み込みができるようにする |
Step 5 | assertを導入 | テストコードのアサーションを最適化する |
Step 6 | karmaを導入 ※step by stepで始めるKarma | ブラウザ上でテストを実行する |
リンク先はソースです。
ゴール
以後Stepの最後にいれていますが
青背景が実行関連のファイル
緑背景がテスト関連のファイル
赤背景がStepごとの差分です。
Step 0 テスト対象アプリケーションを作成
テキストボックスが2つあり計算ボタンを押すと加算して表示するアプリケーションを作成します。
<body>
<div>
<input type="number" id="value1"> + <input type="number" id="value2"> = <span id="result"></span><br>
<input type="button" id="calc" value="計算"></input>
</div>
<script src="/src/calc-util.js"></script>
<script src="/src/index.js"></script>
</body>
document.getElementById('calc').addEventListener('click', function () {
var value1 = Number(document.getElementById('value1').value);
var value2 = Number(document.getElementById('value2').value);
var result = add(value1, value2);
document.getElementById('result').innerText = result;
});
これがテスト対象のコードになります。
function add(value1, value2) {
return value1 + value2;
}
Step 1 ライブラリを使わないでテスト
テスト実行用のhtmlを適当に作ってブラウザで表示、デベロッパーツールでログを見るだけの形です。
<body>
<script src="/src/calc-util.js"></script>
<script src="/test/calc-util-spec.js"></script>
</body>
console.info('add関数のテスト');
console.info('1+2は3である');
if (add(1, 2) === 3) {
console.info('成功')
} else {
console.error('失敗')
}
Step 2 Mochaを導入
前回の状態で一応テストとしては成り立ってはいますが、コンソールエラーを探すとか辛いです。
その問題を解決するために MochaやJasmineというテストフレームワークを使います。
今回はMochaを使ってみます。
テストコードを修正
describeでまとめたりitで検証を定義。
成功だけではつまらないので失敗ケースもついでに追加。
※テスト自体が間違っているだけですが、シンプルにしたいのでm(_ _)m
describe('add関数のテスト', function() {
it('1+2は3である', function() {
if (add(1, 2) === 3) {
} else {
throw new Error('失敗');
}
});
it('1+2は4である', function() {
if (add(1, 2) === 4) {
} else {
throw new Error('失敗');
}
});
});
テスト実行用htmlを修正
css・jsの読み込みやセットアップ処理、出力結果の場所などを追加しています。
<head>
<meta charset="UTF-8">
<title>Step 2 spec</title>
<link href="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.css" rel="stylesheet" />
</head>
<body>
<div id="mocha"></div>
<script src="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.js"></script>
<script>mocha.setup('bdd')</script>
<script src="/src/calc-util.js"></script>
<script src="/test/calc-util-spec.js"></script>
<script>mocha.run();</script>
</body>
実行結果
かっこいい感じの表示になりました。
これならエラーを見つけるのは簡単ですね。
Step 3 Nodejsでテストを実行
修正の都度ブラウザで実行するのも辛いです。
またCIを行うためにもブラウザを使わずにNodejsで実行できるようにする必要があります。
Mochaはnpmでインストールすることでコンソール上から実行が可能になります。
package.jsonを作成
package.json(設定ファイル)を作りたいだけなの返答は適当でOKです
npm init
Mochaをインストール
npm i -D mocha
テストコードを修正
テスト対象コードを読み込むためにrequire
で指定します。
var calcUtil = require('../src/calc-util.js');
describe('add関数のテスト', function() {
it('1+2は3である', function() {
if (calcUtil.add(1, 2) === 3) {
} else {
throw new Error('失敗');
}
});
it('1+2は4である', function() {
if (calcUtil.add(1, 2) === 4) {
} else {
throw new Error('失敗');
}
});
});
テスト対象コードを修正
requireで読み込むには以下のようにmodule.export
で括ります。
※実際に動かす画面が動かなくなりますがこれは次のstepで解消します。まずはテストを通します。
module.exports = {
add : function (value1, value2) {
return value1 + value2;
}
}
package.jsonを修正
以下のようにtestをmochaに修正し、npm test
で実行できるようにします。
※テスト対象のデフォルトがtest/*.js
らしいのでSpecファイルの指定は不要です。
"scripts": {
"test": "mocha",
テスト実行
npm test
Step 4 webpackを導入
requireできるようにadd関数をいじってしまったので画面が動かなくなってしまいました。
これを解決するのが webpack や browserify といったツールを使用します。
今回はwebpackを使用してみます。
webpackをインストール
npm i -D webpack
configファイルを作成
設定の詳細な意味等はこちらの記事webpack入門が分かりやすかったので参照してください。
ざっくり書くとindex.jsとrequireされているcalc-util.jsをapp.bundle.jsにまとめる設定になっています。
touch webpack.config.js
module.exports = {
entry: {
app: './src/index.js'
},
output: {
path: './dist',
filename: '[name].bundle.js'
}
};
package.jsonを修正
以下のようにbuildを追加し、npm run build
で実行できるようにします。
※ webpackとうつだけでデフォルトでwebpack.config.jsが使用されます。
"scripts": {
"test": "mocha",
+ "build": "webpack",
add関数を呼んでいるjsを修正
テストコードと同じ様にrequireを使って以下のようにします
var calcUtil = require('./calc-util.js');
document.getElementById('calc').addEventListener('click', function () {
var value1 = Number(document.getElementById('value1').value);
var value2 = Number(document.getElementById('value2').value);
var result = calcUtil.add(value1, value2);
document.getElementById('result').innerText = result;
});
webpackを実行
npm run build
これでapp.bundle.jsが作成されブラウザで読めるようになりました。
読み込むhtmlを修正
もともと2つ読み込んでいたjsが1つになります。
<body>
<div>
<input type="number" id="value1"> + <input type="number" id="value2"> = <span id="result"></span><br>
<input type="button" id="calc" value="計算"></input>
</div>
<!-- <script src="/src/calc-util.js"></script> -->
<!-- <script src="/src/index.js"></script> -->
<script src="/dist/app.bundle.js"></script>
</body>
副次的にadd関数がグローバル汚染しなくなるというメリットも生まれました。
Step 5 assertを導入
テストをもっと楽にしましょう。
ifやthrowが冗長ですよね。それを可能にするのがassertです。
Nodejsに標準に付属しているライブラリのようです。
require('assert')
を行いassert()
でテスト対象を指定します。
var assert = require('assert');
var calcUtil = require('../src/calc-util.js');
describe('add関数のテスト', function() {
it('1+2は3である', function() {
assert(calcUtil.add(1, 2) === 3);
});
it('1+2は4である', function() {
assert(calcUtil.add(1, 2) === 4);
});
});
だいぶすっきりしました。
Step 6 karmaを導入
今まではNodejsの世界でテストをしていました。
しかしブラウザによって動かない関数を使っていたらエラーになってしまいます。
それを解決するためにkarmaというブラウザ上でテストを動かすライブラリを使います。
karma関連のモジュールをインストール
npm i -D karma karma-chrome-launcher karma-mocha karma-webpack
karmaが本体です。それ以外がプラグインとなっており
karma-chrome-launcherがchrome起動用。
karma-mochaがmocha用。
karma-webpackがwebpack用です。
2016-05-08 追記
karma-cliのグローバルインストールが必要でした。
npm i -g karma-cli
初期設定ファイルを作成
コマンドを叩き質問にこたえることで簡単に設定ファイル(karma.conf.js)を作ることができます。
karma init
Which testing framework do you want to use ?
Press tab to list possible options. Enter to move to the next question.
> mocha
Do you want to use Require.js ?
This will add Require.js plugin.
Press tab to list possible options. Enter to move to the next question.
> no
Do you want to capture any browsers automatically ?
Press tab to list possible options. Enter empty string to move to the next question.
> Chrome
>
What is the location of your source and test files ?
You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".
Enter empty string to move to the next question.
> test/**/*spec.js
18 04 2016 20:26:02.739:WARN [init]: There is no file matching this pattern.
>
Should any of the files included by the previous patterns be excluded ?
You can use glob patterns, eg. "**/*.swp".
Enter empty string to move to the next question.
>
Do you want Karma to watch all the files and run the tests on change ?
Press tab to list possible options.
> yes
Require.jsは必要そうに感じるのですが必要ないです。
※karma-webpackでrequireを変換したファイルを食わせるためです。
karma.conf.jsを修正
上記のまま後述のkarma start
を実行するとUncaught ReferenceError: require is not defined
と出ます。
ブラウザ上で動かしているためrequireが見つからないということですね。
Step 4でwebpackを通してrequireを変換した時と同じことをする必要があります。
karmaではpreprocessorsの設定でwebpackを通すように指定することができます。
preprocessors: {
+ 'test/**/**spec.js': ['webpack']
},
package.jsonを修正
npm test
で実行できるようにするため修正します。
- "test": "mocha",
+ "test": "karma start",
karmaを起動
npm test
Chromeが立ち上がりターミナル上でテスト結果が表示されています。
設定ファイルを作った時の最後の質問でtrueとしているのでテストファイルやテスト対象ファイルを修正した際に、自動でテストが走ります。
テストやソースを修正してからブラウザ画面をF5で更新して確認という手間が省けますね。
余談
図はdraw.ioで1ファイル内で全て作ってpngエクスポートしてそれぞれ範囲選択キャプチャしてます。
良いやり方をご存知でしたらご教示くださいm(_ _)m