Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
書籍転載:JavaScriptライブラリ実践活用[厳選111]

書籍転載:JavaScriptライブラリ実践活用[厳選111]

RSpec風の構文でBDD用のテスト・コードを記述する[Jasmine]

2013年6月13日

書籍転載の11本目(書籍内の番号は「108」)。RSpec風のテスト・コードが書けるBDD(ビヘイビア駆動開発)テスティング・フレームワーク「Jasmine」の基本的な使い方を説明する。

WINGSプロジェクト 高野 将
  • このエントリーをはてなブックマークに追加

書籍転載について

 本コーナーは、技術評論社発行の書籍『JavaScriptライブラリ実践活用[厳選111]』の中から、特にBuild Insiderの読者に有用だと考えられる項目を編集部が選び、同社の許可を得て転載したものです。

 『JavaScriptライブラリ実践活用[厳選111]』の詳細や購入は技術評論社のサイト目次ページをご覧ください。

ご注意

本記事は、書籍の内容を改変することなく、そのまま転載したものです。このため用字用語の統一ルールなどはBuild Insiderのそれとは一致しません。あらかじめご了承ください。

Jasmineは(Rubyでデファクトスタンダードになっている)RSpec風のテストコードを書くための、BDDテスティングフレームワークです。期待する振る舞いをまず定義し、その振る舞いを検証するテストコードを書き、テストを通すように製品コードを書いていきます。
Jasmineを使うと、期待する振る舞いに対して、付随する初期処理、関連するテストを構造化して記述することができるため、テストコードの可読性が上がります。また、検証処理にFluent(流れるような)インタフェースによる検証コードが書けることも特徴です。

Jasmineによるテスト実行結果

テストコード

 Jasmineを利用するには、まずテストコードを用意する必要があります。リスト108-01がFizzBuzz*1のテストコードサンプルです。Jasmineではテストコードを独立したファイルとしてテスト対象コードと対になるように作成し、「(テスト対象コードファイル名)Spec.js」という名前で作成するのが一般的です。

  • *1) 1から順に数え、「3」で割り切れる数の時は「Fizz」、「5」で割り切れる数の時は「Buzz」、「3」と「5」の両方で割り切れる数の時は「FizzBuzz」という遊び

JavaScript
/// <reference path="jasmine.js"/>
/// <reference path="jasmine-html.js"/>
/// <reference path="fizzBuzz.js"/>

// 1テストストーリーの定義
describe("FizzBuzzの正常テスト", function () {
  var fizzBuzz;

  // 4それぞれのテストケースが実行される前に行う処理を記載
  beforeEach(function () {
    fizzBuzz = new FizzBuzz();
  });

  // 2テストケースの定義
  it("数字を返す", function () {
    // 3値の検証
    expect(fizzBuzz.speak(1)).toEqual("1");
    expect(fizzBuzz.speak(2)).toEqual("2");
  });

  it("3の倍数でFizzを返す", function () {
    expect(fizzBuzz.speak(3)).toEqual("Fizz");
    expect(fizzBuzz.speak(6)).toEqual("Fizz");
  });

  it("5の倍数でBuzzを返す", function () {
    expect(fizzBuzz.speak(5)).toEqual("Buzz");
    expect(fizzBuzz.speak(10)).toEqual("Buzz");
  });

  it("3の倍数かつ5の倍数でFizzBuzzを返す", function () {
    expect(fizzBuzz.speak(15)).toEqual("FizzBuzz");
    expect(fizzBuzz.speak(30)).toEqual("FizzBuzz");
  });
});

describe("FizzBuzzの異常テスト", function () {
  var fizzBuzz;

  beforeEach(function () {
  fizzBuzz = new FizzBuzz();
});

  it("引数指定なしで例外発生", function () {
    // 例外の検証
    expect(function () { fizzBuzz.speak(null); })
    .toThrow(new ArgumentNullException());
  });
});
リスト108-01 テストコード(fizzbuzzSpec.js)

 テストコードはユースケースごとにテストストーリーをdescribeメソッドで定義し(.)、テストストーリーに沿った個々のテストケースをitメソッドで定義する(.)、というように構造化して記載します。describeメソッドは入れ子構造にすることも可能です。

 各テストケースでは、expectメソッド、Matcherと呼ばれるアサーションメソッドで値の検証を行います(.)。使用できるMatcherおよびその構文を表108-01に示します。

Matcher構文説明
toBe expect(検証オブジェクト).toBe(期待オブジェクト) 期待オブジェクトと同じオブジェクトかどうか検証する
toEqual expect(検証値).toEqual(期待値) 期待値と同じ値かどうか検証する
toMatch expect(検証値).toMatch(正規表現) 正規表現に合致するかどうか検証する
toBeDefined expect(検証値).toBeDefined() 定義済みかどうか検証する
toBeNull expect(検証値).toBeNull() nullかどうか検証する
toBeTruthy expect(検証値).toBeTruthy() 真とみなせる値かどうか検証する
toBeFalsy expect(検証値).toBeFalsy() 偽とみなせる値かどうか検証する
toContain expect(検証配列).toContain(含まれることを期待する値) 期待した値が配列に含まれているかどうか検証する
toBeLessThan expect(検証値).toBeLessThan(比較値) 比較値より小さい値かどうか検証する
toBeGreaterThan expect(検証値).toBeGreaterThan(比較値) 比較値より大きい値かどうか検証する
toBeCloseTo expect(検証値).toBeCloseTo(比較値, 精度) 指定した精度に丸めた値が比較値と同じかどうか検証する
toThrow expect(検証する処理を行う関数).toThrow(期待する例外オブジェクト) 期待する例外が発生するかどうか検証する
not expect(検証値).not.toBe(期待値) 後続のMatcherの条件を満たさないことを検証する
表108-01 Jasminに既定で用意されたMatcher

 1つのテストストーリー内で共通する初期化処理が必要なら、beforeEachメソッドで定義します(.)。サンプルにはありませんが、共通の終了処理はafterEachメソッドで定義します。

テスト対象コード

 テストコードができたところで、次はテスト対象コードを作成します。Jasmineでは独立したファイルとして作成することが望ましいです。テスト対象コードはリスト108-02のとおりです。

JavaScript
// 引数なし例外
var ArgumentNullException = function () { };

// FizzBuzz用クラス定義
var FizzBuzz = (function () {
  // FizzBuzzクラス作成
  var FizzBuzz = function () { };

  // 指定した値に対応するFizzBuzz結果を返すメソッド
  FizzBuzz.prototype.speak = function (n) {
    // 引数が設定されていなければエラー
    if (!n) throw new ArgumentNullException();
    // 3で割り切れるときはFizz
    if (n % 3 === 0) return "Fizz";
    // 5で割り切れるときはBuzz
    if (n === 5) return "Buzz";
    // 3でも5でも割り切れるときはFizzBuzz
    if (n % 3 === 0 && n % 5 === 0) return "FizzBuzz";
    // 上記いずれでもないときは引数のまま
    return n.toString();
  };

  // 定義したクラスを返す
  return FizzBuzz;
})();
リスト108-02 テスト対象コード(fizzbuzz-test.js)

テスト実行用Webページ

 公式サイトからStandalone版をダウンロードし、その中に含まれる「SpecRunner.html」をコピーして作成します。その際、テストコードとテスト対象コードのインポート部分をリスト108-03のように修正します。

HTML
<!--テスト対象コードをインポート -->
<script type="text/javascript" src="js/fizzbuzz.js"></script>
<!--テストコードをインポート -->
<script type="text/javascript" src="js/fizzbuzzSpec.js"></script>
リスト108-03 テスト実行用Webページ(jasmine.htmlより抜粋)

テスト実行結果

 それではテストを実行してみましょう。リスト108-03で作成したjasmine.htmlをWebブラウザで開くと、図108-01のようにテスト結果が表示されます。各部について説明しましょう。

図108-01 Jasmineによるテスト実行結果

1テストの実行時間

 すべてのテストを実行するのにかかった時間が表示されます。

2テストケースの実行結果マーク

 すべてのテストケースの実行結果をマークで表示します。失敗したテストケースがあると、"×"が表示されます。

3テスト結果の概要

 すべて成功すれば成功したテストケースの数が、一つでも失敗すれば失敗したテストケースの数が概要として表示されます。

4全テストケース数

 すべてのテストケース数が表示されます。この部分はリンクになっており、クリックすると図108-02の全テストケース一覧画面が表示されます。

図108-02 テストケース一覧

 全テストケース一覧画面では、図108-02の枠で囲った部分のようにリスト108-01で記載したテストストーリー、テストケースが階層化されて表示されます。それぞれテストが成功していれば緑、失敗していれば赤で表示されます。

 テストストーリー、テストケースそれぞれはリンクになっていて、クリックすることで指定したテストストーリー、テストケースだけのテストを再実行できます。

 図108-03はテストストーリー「FizzBuzzの正常テスト」をクリックした画面です。この画面の枠で囲った部分には部分実行したテストケース数の概要が表示されます。この部分もリンクになっていて、クリックすることで再度全部のテストケースが実行されます。

図108-03 任意のテストストーリー再実行

5失敗テストケース数

 失敗したテストケース数が表示されます。この部分はリンクになっており、クリックすると失敗したテストケースだけ表示します。

6失敗テストケース

 失敗したテストケースが表示されます。ここにはリスト108-01でテストケースを定義する際、describeメソッドに指定したテストストーリーと、itメソッドに指定したテストケースのテキストが表示されます。

7失敗理由

 テストが失敗した理由が表示されます。検証に利用したMatcherによりメッセージが異なりますが、どのような原因で失敗したのかどうか確認することができます。

 「Expected '10' to equal 'Buzz'.」という結果の内、'10'はexpectメソッドに渡した値、'Buzz'はtoEqualメソッドに渡した値です。この例では'Buzz'を期待したが'10'になってしまっているということになります。

8例外表示設定

 テスト中に例外が発生した場合、既定ではテスト結果として例外が発生したことが表示されます。しかし、例外の表示をブラウザに任せたい場合もあるでしょう。そんなときはここにチェックを入れることで、Jasmineによる例外処理が行われなくなります。

※以下では、本稿の前後を合わせて5回分(第9回~第13回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

書籍転載:JavaScriptライブラリ実践活用[厳選111]
9. [Underscore.js]さなざまなコレクション操作を行う

書籍転載の9本目(書籍内の番号は「100」)。ユーティリティ・ライブラリ「Underscore.js」の基礎として、さまざまなコレクション操作する方法を説明。

書籍転載:JavaScriptライブラリ実践活用[厳選111]
10. [Underscore.js]テンプレートとオブジェクトから文字列を生成する

書籍転載の10本目(書籍内の番号は「101」)。テンプレートとオブジェクトをバインドし、その結果を出力できる「Underscore.js」のテンプレートAPIの使い方を説明。

書籍転載:JavaScriptライブラリ実践活用[厳選111]
11. 【現在、表示中】≫ RSpec風の構文でBDD用のテスト・コードを記述する[Jasmine]

書籍転載の11本目(書籍内の番号は「108」)。RSpec風のテスト・コードが書けるBDD(ビヘイビア駆動開発)テスティング・フレームワーク「Jasmine」の基本的な使い方を説明する。

書籍転載:JavaScriptライブラリ実践活用[厳選111]
12. JasmineのSpy機能でテストダブルを作成する

書籍転載の12本目(書籍内の番号は「109」)。Jasmineでテスト対象オブジェクトが持つメソッドの戻り値を固定値に変更したり、そのメソッドが実行されたかどうかを検証したりするために、Spy機能を使用する方法を解説。

書籍転載:JavaScriptライブラリ実践活用[厳選111]
13. 短くかつ安全で高性能なコードを書く[CoffeeScript]

書籍転載の13本目(書籍内の番号は「62」)。短い記述で、安全かつ高性能なJavaScriptコードを生成できる「CoffeeScript」の基本的な使い方を説明する。

サイトからのお知らせ

Twitterでつぶやこう!