一から勉強させてください( ̄ω ̄;)

最下級エンジニアが日々の学びをアウトプットしていくだけのブログです。

jasmineつかってみた

今回はJavaScriptのテストフレームワークjasmineをつかってみたときのことを書きたいと思います。


近年、テストを先に書いてから実装を行う

テスト駆動開発(TDD: Test Driven Development )」

というものが注目されておりましたが、最近はそのさらに進化版の

「振る舞い駆動開発(BDD: Behavior Driven Development)

とやらも注目されておるみたいであります。


ま、正直その違いもいまいちよくわかってないんですが、、

わかりやすく書いてくださっている方もいらっしゃったので、その恩恵を受ける事にします。。ありがとうございます。

http://ukstudio.jp/2011/07/02/bdd/


BDDではあらかじめ実装するアプリケーションに期待する「振る舞い」をコードで書いておき(この振る舞いをスペックっていうぽいです)、それを満たすように開発を進めていきます。

んで、そのBDDの代表的なフレームワークがjasmineてことですな。


では早速、jasmineの導入〜動作確認までを順に書いていきたいと思います。


1、jasmineのダウンロード

まずはダウンロード。

jasmineは

スタンドアロン版を使うパターン
Rubyアプリケーションに組み込んで使うパターン

の2通りの使い方があるらしいのですが、今回はスタンドアロン版を導入することにします。(スタンドアロン版ではブラウザで結果を確認するみたいですが、PhantomJSを使って自動化もできるぽいです)


ダウンロードはこちらから。今回は1.3.1をダウンロードしました。
https://github.com/pivotal/jasmine/downloads


ダウンロードしたものを開いてみると、以下のようなディレクトリ構成です。

jasmine-standalone-1.3.1
ーsrc
 ーPlayer.js
 ーSong.js
ーspec
 ーPlayerSpec.js
 ーSpecHelper.js
ーlib
 ーjasmine-1.3.1
  ーjasmine-html.js
  ーjasmine.js
  ーjasmine.css
ーSpecRunner.html


まずjasmineのコアとなるのがlibにある「jasmine.js」で、テスト結果をHTMLに出力する役割を果たすのが「jasmine-html.js」みたいですね。
jasmine.jsはサバクラ両方で動作するスクリプトっぽいので、動作確認はサーバーにあげてやらないとだめっぽいです。


んで、srcにテスト対象となるコード(実装用のコード)、specにスペックを記述したコードを入れてあげればいいみたいです。
サンプルとして、Player.js, Song.js, PlayerSpec.js, SpecHelper.jsを用意してくれていますね。これの真似して書いていけば良いぽいです。スペックがすべて通るように、実装用のコードを仕上げていくっていうイメージでしょうか。


実際の結果はSpecRunner.htmlで確認できます。
SpecRunner.htmlで読み込んでるファイルパスを変えてやれば、別にこの構成に従う必要もないっぽいですね。


それではこれらをMAMPを使って、動作確認していきたいと思います。


2、動作確認

それでは早速動作確認を!


、、の前にMAMPmysqlがうまく起動しないという、おなじみのエラーが発生したので、まずそこを直します…
でもこれは余裕ですよ!参考になる情報も多いですからね!!

http://www.mikawalamp.com/tips/mamp_mysql/

ターミナルで

killall -9 mysqld

を実行してやればすぐ直りました。


では今度こそ動作確認です。
(サンプルで入ってたPlayer.js, Song.js, PlayerSpec.js, SpecHelper.jsはいったん削除してます)


ためしにこんなコードを書いてみました。

・実装側 src/Cat.js

var Animal = function(){};
Animal.prototype.breathe = function(){
	console.log("ふーふー");
}

var Cat = function(){};
Cat.prototype = new Animal;

Cat.prototype.cry = function(){
	console.log("にゃーにゃー");
}


・スペック spec/CatSpec.js

describe("cat", function(){
	var cat = new Cat;

	it("cryメソッドを持っている", function(){
		expect(cat.cry).toBeDefined();
	});

	xit("breathメソッドを継承している", function(){
		expect(cat.breathe).toBeDefined();
	});

	it("catはAnimalである", function(){
                expect(cat).toEqual(jasmine.any(Animal));
	});

});


src/Cat.js側は、よくありがちなAnimalを継承するCatのインスタンスを用意しただけです。
んで、spec/CatSpec.jsにはjasmineの記述方式に従ってスペックを書いてみました。


もうちょっとCatSpec.jsについて詳しく見てみます。


ひとまず基本的な書き方としては
describe関数でコンテキストを指定し、it関数で個々のスペックを書いていきます。


今回はcatというインスタンスについて、

・cryメソッドを持っているか
・Animalをちゃんと継承しているか

を確認してみました。(実際にはこんなことしないかも…)


itの中身ですが、
スペックではexpect関数に実際の値(actual)を指定して、その結果と期待値をMatcherと呼ばれるメソッドを使って確認していきます。


今回の一つ目のitでは

expect(cat.cry).toBeDefined()

と書いていますが、これのactualとMatcherはそれぞれ

actual → cat.cry
Matcher →toBeDefined()

となります。

その結果、これは実際にcatに定義しているメソッドなので真となり、スペックを通ります。


二つ目のitでは同様にbreatheメソッドを持っているか確認しようとしたのですが、これはAnimalをうまく継承できていれば当然もってるので、そっちをメインにテストしてみようと方向性を変えました。

もちろんコメントアウトしてもいいんですが、そんな時便利なのが、「x」。
describeとitは、前にxを付ける事でその部分を無視してくれるようになってるみたいですね。今回xitとしてみたのですが、ちゃんとその部分は無視してくれてました。


最後に三つ目のitですが、
ここで先ほど書いたAnimalをうまく継承できているかを確認してます。

jasmine.anyにコンストラクタを指定する事でそのクラスのインスタンスを表現する事ができるので、toEqualでつないで、catがAnimalのインスタンスであることを確認してみました。ちゃんと真になりますね。


以上を、実際にSpecRunner,htmlに指定して見てみると以下のようになります。

f:id:d_animal141:20130901142441p:plain


二つのスペックが問題なく通ったらこんな感じで緑デザインの画面になります。


もしどこかに問題があった場合、たとえば最後のitの中身を

it("catはArrayである", function(){
    expect(cat).toEqual(jasmine.any(Array));
});

としたら以下のような結果になります。


f:id:d_animal141:20130901143015p:plain

catはArrayではないので、がっつりエラーが出ますね。赤いです。


こんな感じでテストしながら実装ができるのかーというイメージぐらいは掴む事ができました。


本当はもっとたくさんのMatcherがあったり、独自でつくれたり、他にも機能はたくさんあるっぽいのですが、今回はここまでにしておきます。

今後はこのようなテストも取り入れて、より精度の高い実装ができればと思います。


小さなことからコツコツと。