angular.jsをやってみる (12) - angular-mocks.jsを使ったテスト -

2014-03-27T00:00:00+00:00 angular.js JavaScript

今まで

angular.jsのkarmaを使ったテスト
protractorを使ったangular.jsのe2eテスト

っていうのをやってたけど、angular-mocks.jsを使う事での単体テストすることも可能な模様なので色々整理する辺りな所としてやってみた

sample.js

var SampleController = (function() {

  function SampleController($scope, $http) {
    $http.get("/samples").success(function(samples) {
      $scope.samples = samples;
    });
  };

  return SampleController;

})();

っていう感じでangular.jsの$httpを使ってAPI呼び出しなりをしてデータを取得後$scopeに突っ込むという単純なangular.jsのコントローラーを定義

まぁこれを単体テストしましょうってことなので(ry

mocha.html

テストにmochaを使う。なのでテストランナーなHTMLを作る

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Mocha</title>
    <link rel="stylesheet" href="mocha.css" />
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.3/angular.js"></script>
    <script type="text/javascript" src="mocha.js"></script>
    <script type="text/javascript" src="chai.js"></script>
    <script type="text/javascript">
      chai.should();

      var expect = chai.expect;
      mocha.setup({ "ui": "bdd", "timeout": 3000, "ignoreLeaks": false });
    </script>

    <!-- 上記コントローラーなJS -->
    <script type="text/javascript" src="sample.js"></script>
  </head>
  <body style="background: #bbb">
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.3/angular-mocks.js"></script>
    <!-- テストスペック -->
    <script src="test.js"></script>
    <div id="mocha"></div>
    <script>
        mocha.run();
    </script>
  </body>
</html>

な感じで。これでテストスペック上でinject等が使えるのでこれを利用して$httpを利用して返されるレスポンスをテストしたり出来る

test.js

describe("Sample", function() {

  var $controller;
  var $httpBackend;

  function createController(scope) {
    return $controller("SampleController", { "$scope": scope });
  }

  beforeEach(
    inject(function($injector) {
        $controller = $injector.get("$controller");
        $httpBackend = $injector.get("$httpBackend");
        $httpBackend
          .when("GET", "/samples")
          .respond([{ name: "hoge" }, { name: "fuga" }]);
    })
  );

  afterEach(function() {
    // flushで呼ばれるので必要ないのでは?
    // リクエスト発生してないのにflushするとthrow new Errorされる
    // $httpBackend.verifyNoOutstandingExpectation();

    // flushしてないとthrow new Errorされる
    $httpBackend.verifyNoOutstandingRequest();
  });

  it("constructor", function() {
    var scope = {};
    var sample = createController(scope);
    $httpBackend.flush();

    expect(scope.samples).not.to.be.empty;
    // 実際に返される値数は2 (when -> respondで返してる配列の要素数が2だから)
    expect(scope.samples).to.have.length(3);
  });
});

っていう感じで。あとはテストランナーなHTMLを普通にブラウザで開けば良い。それをやると

っていうような結果が得られる。

んまぁangular.jsなコントローラーとかの単体テストをする場合とかでangular.jsなproviderやserviceが必要になる要件な場合とかだとangular-mocks.jsを使う事で擬似オブジェクトを利用したテストを利用できるっていう感じかと

angular.jsをやってみる (13) - $sceとngSanitize - angular.jsをやってみる (11) - $interval -