JavaScriptのテストフレームワークJasmineでできる基本的なこと
JasmineはJavaScriptのテストフレームワークです。RailsでいうRSpecのようなものでより簡単にテストを記述することができます。自分への備忘録の意味も含めていろいろ調べて見ようと思います。今回はその中でも記述方法にフォーカスして書こうと思います。
Jasmineの基本
Jasmineを利用したテストスイートは、 describe
という関数から始まります。 describe
には引数にテストのタイトル(文字列)と実際に実行するコードブロック(関数)を渡すことができます。
スペック
it
は実際のスペックを記述するところになります。これも describe
と同様にこのスペックのタイトル(文字列)とそのスペックを実現するためのコードブロック(関数)を引数として渡すことができます。以下が describe
と it
を使用した簡単なテストコードになります。
describe("sample", function() {
it("2 + 2 equal 4", function() {
expect(2 + 2).toEqual(4);
});
});
またスペックにはコードの状態をテストする1つ以上のexpectationがなければいけません。Jasmineのテストは真か偽かで表現され、全てのスペックが真であればそのテストは合格となり、一つでも偽があればそのテストは不合格となります。
describe
や it
の第二引数は関数です。関数には実行可能なコードを含めることができます。ここではJavaScriptのスコープを適応することができ、また describe
のブロック内に記述した変数などはその describe
内のどの it
からでも使用することができます。
Expectation
Expectationは expect
関数でビルドされます。この関数は、指定した値と実際に呼ばれて取得することができる値を取ります。またそれは期待値を取得するMatcher functionとchainすることができます。またMatcherはカスタムすることもできます。
具体的にどんなMatcher functionが使えるのか見ていきましょう。またすべてのMatcher functionには .not
と一緒につなげることで反対の意味にすることも可能です。
toBe: 実際の値が期待している値を同じであることを期待する
toEqual: toBeと同じ(それは文字列、数字、連想配列でも同じ)
toMatch: 実際の値が期待している文字列をマッチしていることを期待する(文字列の完全一致でも正規表現を使ったマッチでも可)
toDefined: undefined出ないことを期待する
toBeNull: nullであることを期待する
toBeTruthy: trueであることを期待する
toBeFalsy: falseであることを期待する
toContain: 実際の値が期待している値の中に含まれていることを期待する(文字列に対して)
toBeGreaterThan: 実際の値が期待している値より大きいことを期待する(整数、浮動小数点)
toBeLessThan: 実際の値が期待している値より小さいことを期待する
toBeCloseTo: 数学的に精密な比較をするために使用される
toThrow: 関数が例外を発生したかを期待する
describe
は関連するスペックをグループ化するための関数でもあります。そのためタイトルに入れている文字列は describeとit
を連結してフルネームを生成します。
SetupとTeardown
このテストスイートはsetupとteardownを実現するために beforeEach
と afterEach
関数を用意しています。これらの関数はそれぞれスペックが実行される前と後に実行される関数になります。
beforeEach, it, afterEach
間で変数を共有する方法としてthisがあります。
また describe
はネストさせることができます。
テストを無効にする
テストを無効、スキップさせる方法として、 xdescribe, xit, pending
があります。
xdescribe("sample", function() {
xit("sample spec", function() {
pending();
});
});
スパイ
SpyとはJasmineが用意しているテストダブル機能を実現させるためのものです。
テストダブルとは、テスト対象が依存しているコンポーネントを置き換える代用品のこと。参照: https://ja.wikipedia.org/wiki/%E3%83%86%E3%82%B9%E3%83%88%E3%83%80%E3%83%96%E3%83%AB
スパイは、すべての関数をスタブし、その関数とすべての引数の呼び出しを追跡することができます。スパイは、それが定義されている記述ブロックまたはブロックのみに存在し、各スペックの後に削除されます。
そしてスパイに対するMathcer functionも存在します。
toHaveBeenCalled: スパイが呼び出されたときにtureを返す
toHaveBeenCalledWith: 引数リストがスパイに記録されているどんなものにマッチしている場合はtrueを返す
describe("spy sample", function() {
var foo, bar = null;
beforeEach(function() {
foo = {
setBar: function(value) {
bar = value;
}
};
spyOn(foo, 'setBar');
foo.setBar(123);
foo.setBar(456, 'another params');
});
it("sample spy", function() {
expect(foo.setBar).toHaveBeenCalled();
});
it("sample spy with args", function() {
expect(foo.setBar).toHaveBeenCalledWith(123);
});
});
またスパイの spyOn()
に続けて、 .and.callThrough()
をchainさせることでスパイとして呼び出しを追跡しますが、実際の関数も呼び出されます。
.and.returnValue()
でchainすることにより関数へのすべての呼び出しは特定の値を戻り値として返します。
.and.callFake()
でchainすることによりスパイへのすべての呼び出しを指定された関数に委譲することができます。
spyOn(foo, "sample").and.callFake(function(args) {
return true
});
もしスパイになっている関数にfakeが求めている引数を受け取ればそれらも同時に取得することができます。
.and.throwError()
でchainするとスパイは特定の例外を返します。
.and.stub()
でchainするとスパイとして使われているコーリングストラテジーをスタブの振る舞いで何回でも返すことができます。
他の追跡プロパティ
スパイへのすべての呼び出しは呼び出しプロパティで追跡、公開することができます
.calls.any(): スパイが全く呼び出されていない場合は、falseを返し、1回以上呼び出されている場合は、trueを返す
.calls.count(): 呼び出された回数を返す
.calls.argsFor(index): インデックスに渡された引数を返す
.calls.allArgs(): すべての呼び出しに渡した引数を返す
.calls.all(): thisとすべての呼び出しに渡した引数を返す
.calls.mostRecent(): 直前の呼び出しのthisと引数を返す
.calls.first(): 最初に呼び出されたthisと引数を返す
.calls.reset(): すべての追跡をクリアする
all(), mostRecent(), first()
から戻り値を調べるときはオブジェクトのプロパティはスパイが呼び出されたときのthisの値に設定されます。
スパイする機能がない場合は、 jasmine.createSpy
で素のスパイを作成することができます。様々な用途で使用することができますが、そのスパイは実装されているわけではなくJavaScriptオブジェクトであり、そのように使用することができます。
複数のスパイを持つモックを作成するには、 jasmine.createSpyObj
を使用して文字列の配列を渡します。それによりスパイである各文字列のプロパティを持つオブジェクトを返します。
Matcher Anying with jasmine.any
jasmine.any
はクラス名またはコンストラクタを期待値として取得します。コンストラクタが実際の値と一致していればtrueを返します。
jasmine.onjectContaining
はキーとバリューのペアを実際の値として気にしています。
タイムアウト関数のJavaScriptのモック
Jasmine Clockは setTimeout
または、 setInterval
コールバックを使用する必要があるテストスイートで使用できます。タイマーのコールバックを同期させてクロックが時間内に前方にチェックされると登録された関数を実行します。
タイマーの関数を使用したい場合には、 beforeEach
で jasmine.clock().install();
と afterEach
で jamine.clock().uninstall();
を実行する必要があります。
tick
関数を使用することでコールバックへの呼び出しの時間を指定することができます。これはミリ秒単位で指定することができます。
非同期テスト
Jasmineは2.0から非同期のテストをサポートするようになりました。
beforeEach, it, afterEach
への呼び出しは、非同期作業が完了したときに呼び出される単一の引数を取ることができます。
デフォルトではJasmineは非同期の describe
が終了するまでに5秒待機します。 done
が呼び出される前にタイムアウトになると失敗とみなされます。待機時間を指定する場合は、 jasmine.DEFAULT_TIMEOUT_INTERVAL
を設定することで調整することができます。またこれはグローバルに設定することができます。
参照リンク