こんにちはDMM.comラボCTO室の加嵜です。
記念すべきDMMエンジニアブログの第1回目ということで、今回は、mochaというJavaScriptのテスティングフレームワークと、mocha-phantomjsを使って、クライアントサイドのJavaScriptテストの自動化を紹介します。
mochaでテスト駆動開発
まず、mochaを使ってクライアントサイトJavaScriptの簡単なテスト駆動開発を実践してみます。
今回使用するのは、mocha本体と、mochaでアサーションを記述するためのchaiというライブラリです。
mocha
http://mochajs.org/
chai
http://chaijs.com/
事前準備
事前準備として、htmlで読み込むmocha.js, mocha.css, chai.jsファイルを入手します。npm, bower等を使って自動でダウンロードすることもできますが、今回は最低限のファイルとして、下記の3つを手動でダウンロードしてみます。
mocha.js
https://raw.githubusercontent.com/mochajs/mocha/master/mocha.js
mocha.css
https://github.com/mochajs/mocha/blob/master/mocha.css
chai.js
http://chaijs.com/chai.js
上記のファイルを、下のhtmlファイルのように読み込んで、mochaのテストをセットアップします。
mochaのインターフェイスはTDD形式/BDD形式から選べます。今回はBDD形式を採用しています。
chaiのアサーションの形式は、should形式/expect形式/assert形式から選べます。
今回はexpect形式を採用しています。
ファイルの読み込みとJavaScriptのセットアップだけでなく、body内にid=”mocha”のdiv要素を追加するのを忘れないで下さい。
test/sample0.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/mocha.css" />
<script src="js/mocha.js"></script>
<script src="js/chai.js"></script>
</head>
<body>
<div id="mocha"></div>
<script>
mocha.setup('bdd');
mocha.reporter('html');
var expect = chai.expect;
describe("サンプルテスト", function() {
it("テストケースを記述");
});
mocha.run();
</script>
</body>
</html>
このhtmlファイルをブラウザで開くと、下のような画面になります。
Step.1 inputのバリデーションテスト実装
今回のサンプルプログラムとして、メールアドレスの入力フォームのバリデーション機能を扱ってみます。
まず、メールアドレスの入力フォームとバリデーションメッセージの出力欄、送信ボタンを持つform要素を作ります。
<form id="myform">
<input id="validate-mail" type="text" />
<span id="invalid-message"></span><br />
<input type="submit" />
</form>
一旦、送信ボタンを押しても実際に送信が実行されないよう、空のファンクションを設定しておきます。
<script src="js/jquery.min.js"></script>
<script>
<script src="js/jquery.min.js"></script>
<script>
$(function() {
$('#myform').bind('submit', function(event) {
event.preventDefault();
});
});
</script>
続いて、mochaのdescribeの中に、このフォームを送信した際のバリデーションの挙動を記述していきます。
完成したhtmlファイルが、次のsample1.htmlです。
test/sample1.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/mocha.css" />
<script src="js/mocha.js"></script>
<script src="js/chai.js"></script>
</head>
<body>
<div id="mocha"></div>
<form id="myform">
<input id="validate-mail" type="text" />
<span id="invalid-message"></span><br />
<input type="submit" />
</form>
<script src="js/jquery.min.js"></script>
<script>
$(function() {
$('#myform').bind('submit', function(event) {
event.preventDefault();
});
mocha.setup('bdd');
mocha.reporter('html');
var expect = chai.expect;
describe("validation", function() {
var $mail = $('#validate-mail'),
$form = $('#myform'),
$msg = $('#invalid-message');
it("empty mail", function() {
$mail.val('');
$form.submit();
expect($msg.text()).to.equal('入力必須です');
});
it("invalid mail", function() {
$mail.val('xxxx');
$form.submit();
expect($msg.text()).to.equal('不正なメールアドレスです');
});
it("valid mail", function() {
$mail.val('xxxx@xx.com');
$form.submit();
expect($msg.text()).to.equal('');
});
});
mocha.run();
});
</script>
</body>
</html>
このhtmlファイルをブラウザで開くと、まだバリデーション機能を実装していないので、テストが失敗します。
Step.2 バリデーション機能実装
テストが失敗することを確認したら、そのテスト成功するように、実際の機能を実装していきます。submit部分のファンクションを下記のように変更します。
test/sample2.html
$('#myform').bind('submit', function(event) {
event.preventDefault();
var mail = $('#validate-mail').val(),
re = /\S+@\S+\.\S+/;
if (mail.length === 0) {
$('#invalid-message').text('入力必須です');
} else if(!re.test(mail)) {
$('#invalid-message').text('不正なメールアドレスです');
} else {
$('#invalid-message').text('');
}
});
ブラウザで確認すると、テストが成功に変わりました。続いて、テストが成功することを確認しながら、必要に応じてファンクションの中身をリファクタリングしていきます。
Step.3 grunt-mocha-phatomjsでテストの自動化
ブラウザでのテストを実行することができましたが、対象ファイルが増えてくると、コマンドですべてのテストを自動化できるようにしたくなります。
最後に、gruntとmocha_phantomjsを導入して、クライアントJavaScriptのテストを自動化してみます。
※ gruntを導入するためにnpmを使用しますので、必要に応じてnpmをインストールしてください。
gruntのコマンドを使えるようにします。
npm install -g grunt-cli
grunt-mocha-phantomjsをインストールします。
npm install grunt-mocha-phantomjs --save
サーバを立ててファイルをhttpでアクセスするために、grunt-contrib-connectをインストールします。
npm install grunt-contrib-connect --save
htmlファイルで、mocha.run()となっていた部分を、phantomjsで扱えるように修正します。
test/sample3.html
if (window.mochaPhantomJS) {
mochaPhantomJS.run();
}
else {
mocha.run();
}
Gruntfile.jsファイルを下記のように設定します。
Gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
connect: {
server: {
options: {
port: 8080,
base: '.',
keepalive: true
}
}
},
mocha_phantomjs: {
all: {
options: {
urls: [
'http://localhost:<%=connect.server.options.port%>/test/sample3.html'
]
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-mocha-phantomjs');
grunt.registerTask('default', ['connect', 'mocha_phantomjs']);
};
gruntのdefaultタスクにconnectとmocha_phantomjsを登録しているので、コマンドラインでgruntを実行すると、サーバが起動し、mochaテストが実行されます。
grunt
Running "mocha_phantomjs:all" (mocha_phantomjs) task
validation
✓ empty mail
✓ invalid mail
✓ valid mail
3 passing (35ms)
最後に
クライアントサイドのJavaScriptのテストは、サーバサイドのテストと比べて環境整備が遅れていましたが、mocha-phantomsjsなどの自動化ツールによって実現しやすくなってきました。
さらに、Gruntなどのビルドツールと組み合わせることで、サーバサイドJavaScriptとの連携やminifyなどの作業と統合的に実行することが可能となっています。