Pocket

こんにちは!ishibashiです。

今回はJavascriptのテストフレームワーク「Jasmine」を紹介します。

Jasmineは、RSpec(http://rspec.info/)に近い記法を使ってJavaScriptのテスティングを行うフレームワークです。

Jasmineは(https://github.com/pivotal/jasmine/downloads)からダウンロードできます。

では早速実際にJasmineを使って、テストをしてみたいと思います。

ファイルの構成は以下のようになっています。

ダウンロードしたファイルにはサンプルファイルも入っているので、今回はそれをもとに説明していきたいと思います。

それではソースの中身を見ていきましょう。

テスト対象クラスは以下のようになっています。

function Player() {
}
Player.prototype.play = function(song) {
  this.currentlyPlayingSong = song;
  this.isPlaying = true;
};

Player.prototype.pause = function() {
  this.isPlaying = false;
};

Player.prototype.resume = function() {
  if (this.isPlaying) {
    throw new Error("song is already playing");
  }

  this.isPlaying = true;
};

Player.prototype.makeFavorite = function() {
  this.currentlyPlayingSong.persistFavoriteStatus(true);
};

これに対するテストクラスは以下のように記述します。

// `describe`メソッドにクラス等のテスト対象を記述します。
describe("Player", function() {
  var player;
  var song;

  beforeEach(function() {
    player = new Player();
    song = new Song();
  });

  // `it`メソッドにテスト実施内容を記述します。
  it("should be able to play a Song", function() {

    // テスト内容を記述します。
    player.play(song);

    // 期待値との比較を行います。
    expect(player.currentlyPlayingSong).toEqual(song);

    // 期待値との比較を複数回行うことができます(一つでも期待値に一致しない場合はNG)。
    expect(player).toBePlaying(song);
  });

  // `describe`メソッドの中に`describe`メソッドを追加することもできます。
  describe("when song has been paused", function() {
    beforeEach(function() {
      player.play(song);
      player.pause();
    });

    // 上記と同じように`it`メソッドにテスト内容を記述します。
    it("should indicate that the song is currently paused", function() {
      expect(player.isPlaying).toBeFalsy();

      // demonstrates use of 'not' with a custom matcher
      expect(player).not.toBePlaying(song);
    });

    it("should be possible to resume", function() {
      player.resume();
      expect(player.isPlaying).toBeTruthy();
      expect(player.currentlyPlayingSong).toEqual(song);
    });
  });

  // demonstrates use of spies to intercept and test method calls
  it("tells the current song if the user has made it a favorite", function() {
    spyOn(song, 'persistFavoriteStatus');

    player.play(song);
    player.makeFavorite();

    expect(song.persistFavoriteStatus).toHaveBeenCalledWith(true);
  });

  //demonstrates use of expected exceptions
  describe("#resume", function() {
    it("should throw an exception if song is already playing", function() {
      player.play(song);

// 異常系のテストは以下のように記述します。
      expect(function() {
        player.resume();
      }).toThrow("song is already playing");
    });
  });
});

※1 日本語のコメントは後から追加しました。

このテストを実行してみます。

SpecRunner.htmlは以下のように記述します。

</pre>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
 <title>Jasmine Spec Runner</title>

<link rel="shortcut icon" type="image/png" href="lib/jasmine-1.2.0/jasmine_favicon.png">
 <link rel="stylesheet" type="text/css" href="lib/jasmine-1.2.0/jasmine.css">
 <script type="text/javascript" src="lib/jasmine-1.2.0/jasmine.js"></script>
 <script type="text/javascript" src="lib/jasmine-1.2.0/jasmine-html.js"></script>

<!-- テストファイルを読み込みます -->
 <script type="text/javascript" src="spec/SpecHelper.js"></script>
 <script type="text/javascript" src="spec/PlayerSpec.js"></script>

<!-- テスト対象ファイルを読み込みます -->
 <script type="text/javascript" src="src/Player.js"></script>
 <script type="text/javascript" src="src/Song.js"></script>

<script type="text/javascript">
 (function() {
 var jasmineEnv = jasmine.getEnv();
 jasmineEnv.updateInterval = 1000;

var htmlReporter = new jasmine.HtmlReporter();

jasmineEnv.addReporter(htmlReporter);

jasmineEnv.specFilter = function(spec) {
 return htmlReporter.specFilter(spec);
 };

var currentWindowOnload = window.onload;

window.onload = function() {
 if (currentWindowOnload) {
 currentWindowOnload();
 }
 execJasmine();
 };

function execJasmine() {
 jasmineEnv.execute();
 }

})();
 </script>

</head>

<body></body>
</html>

実行結果

すべてのテストが成功しました。

エラーがある場合は以下のように表示されます。

・実行結果一覧画面(エラーのテストは赤字で表示されます)

・実行詳細画面

このように簡単にJavascriptのテストが実施できます。

今回の説明では詳しく触れませんが、Jasmineは非同期な動作もテストすることが出来ます。

またCI(継続的インテグレーション)に統合することも可能です。

興味のある方は参考にしてみてください。

ではでは~