こんにちは、プログラマのおぐらです。毎度おなじみ流浪のJasmineチュートリアルをお送りします。
前回のJasmineによるJavaScriptのテスト その3では、beforeEach
とafterEach
による「テストの事前準備と後始末」について解説しました。今回は実際にテストを記述する部分を詳細に説明していきます。
テストコード
Jasmineでは、テストコードがそのまま英文として読めるように設計されています(これはビヘイビア駆動開発の特徴でもあります)。
expectメソッドとMatcherメソッド
xUnit系のテスティングフレームワークにおけるassert
系メソッドに相当するものが、expect
メソッドとMatcherメソッドです。
テスト対象であるvalue
が期待値である「5」と同一であることを検証する場合、xUnit系では、
assertEquals(5, value);
のように書きますが、Jasmineでは、
expect(value).toEqual(5);
のように書きます。
このように、Jasmineのテストコードは「expect
メソッドが返すオブジェクトのtoXXXXX
メソッドで、テスト対象が期待値どおりであるかどうかを評価する」という構造になっており、toXXXXX
のような評価用のメソッドをMatcherと呼びます。
定義済みのMatcher
Jasmineでは以下のMatcherが定義されており、さらに自分で定義することもできます。
Matcher | 意味 |
---|---|
expect(a).toEqual(b)
|
a がb と同値であることを期待する
|
expect(a).toBe(b)
|
a がb と同一オブジェクトであることを期待する
|
expext(a).toBeDefined()
|
a が定義されていることを期待する(undefined でない)
|
expect(a).toBeNull()
|
a がnull であることを期待する
|
expect(a).toBeTruthy()
|
a がtrue であることを期待する
|
expect(a).toBeFalsy()
|
a がfalse であることを期待する
|
expect(a).toContain(b)
|
a にb が含まれていることを期待する
|
expect(a).toBeLessThan(b)
|
a がb より小さいことを期待する
|
expect(a).toBeGreaterThan(b)
|
a がb より大きいことを期待する
|
expect(fn).toThrow(e)
|
fn が例外をスローすることを期待する
|
上記の一覧にはa != b
のように否定形をテストするものがありませんが、Jasmineではexpect(a).toEqual(b)
の否定形は、
expect(a).not.toEqual(b);
のように、expect
メソッドとMatcherメソッドの間にnot
をはさむことで表現します。
DOM操作を伴うテストの書き方
JasmineにはDOM操作を行う機能が提供されていません。そのため、テスト用のDOM要素は自分で用意する必要があります。
テストの準備
お馴染みのdocument.getElementById
メソッドのテストを書いてみましょう。まず、新しくプロジェクトディレクトリにspec/DocumentSpec.js
を作成します。
このテストでは「getElementById
でIDがtest-node
のDOM要素を取得し、その結果がnull
ではないこと」をテストしています。
次に、このspec/DocumentSpec.js
を読み込むためにSpecRunner.html
を以下のように変更します(第2回の「最初のテスト」で作成したSpecRunner.html
の12行目にあるspec/ArraySpec.js
をspec/DocumentSpec.js
に変更しただけです)。
「SpecRunner.html
を編集してテストファイルを読み込む」という作業はテストを追加した際に必ず必要となりますが、以降は記載を省略します。新しいテストファイルを追加した際は、適時SpecRunner.html
を編集するようにしてください。
テストの実行
それではテストを実行してみましょう。ブラウザでSpecRunner.html
を開いてみます。
テストは失敗となりました。
このテストでは、
var elementId = 'test-node';
expect(document.getElementById(elementId)).not.toBeNull();
という箇所で「DOMツリーにtest-node
というIDを持ったDOMノードがあること」を期待しています。しかし、test-node
というIDを持つノードは存在していないため、document.getElementById('test-node')
がnull
を返し、その結果テストが失敗したわけです。
SpecRunner.html
のbody
要素内に<div id="test-node"></div>
という記述を追加すればテストは成功しますが、そうするとすべてのテストがSpecRunner.html
の内容に依存してしまいます。これを回避するには、beforeEach
とafterEach
を使ってテスト時に動的にDOMツリーを操作する必要があります。
動的にDOMツリーを操作
DocumentSpec.js
を以下のように編集し、beforeEach
メソッドとafterEach
メソッドを追加します。
beforeEach
では、document
オブジェクトのcreateElement
とappendChild
を利用してbody
要素にテスト用のdiv
要素を新しく追加しています。また、追加した要素をafterEach
メソッドから参照できるよう、container
という変数に格納しています。
afterEach
では、後始末としてテスト用に追加したDOM要素をdocument.body
から削除しています。
では、再度テストを実行してみましょう。
無事にテストが成功しました。
jasmine-domによるDOM構造の準備
jasmine-domを導入すると、先程のテストを以下のように簡潔に書くことができます。
だいぶスマートに記述できました。
Jasmineには、他にもjQuery用の拡張やiPhone用の拡張などがあり、Related Projectsにてアドオンの一覧が紹介されているので、参考にしてみてください。
今回はここまで。次回は最終回として「モック、スタブを使用したテストの書き方」について解説したいと思います。