AngularJSの単体テストを書く

Jasmine を使って AngularJS の単体テストコードを書く。

#コントローラとかを個別の関数として定義している場合
```text:フォルダ構成
|-test.html      : テストを動かすための html.
|-controllers.js : コントローラを定義した js.
|-app.js         : AngularJS の設定をしている js.
|-test.js        : Jasmine のテストコード.
|-jasmine/       : Jasmine のファイル類.
`-angular/       : AngularJS のファイル類.
```

```js:controllers.js
var mine = {
    controllers: {
        SampleController: function($scope) {
            $scope.message = 'Hello SampleController!!';
          
            $scope.click = function() {
                $scope.message = 'clicked!!';
            };
        }
    }
};
```

```js:app.js
angular
.module('mine', [])
.controller('SampleController', mine.controllers.SampleController);
```

```js:test.js
describe('suite', function() {
    var controller,
        $scope;
  
    beforeEach(function() {
        $scope = {};
        controller = new mine.controllers.SampleController($scope);
    });
  
    it('spec', function() {
        expect($scope.message).toBe('Hello SampleController!!');
      
        $scope.click();
      
        expect($scope.message).toBe('clicked!!');
    });
});
```

```html:test.html
<!doctype html>
<html>
  <head>
    <link href="jasmine/jasmine.css" rel="stylesheet"/>
    <script src="jasmine/jasmine.js"></script>
    <script src="jasmine/jasmine-html.js"></script>
    <script src="jasmine/boot.js"></script>
    <script src="jasmine/console.js"></script>
    
    <script src="angular/angular.min.js"></script>
    
    <script src="controllers.js"></script>
    <script src="app.js"></script>
    <script src="test.js"></script>
  </head>
  <body>
  </body>
</html>
```

- 普通にコントローラをインスタンス化して、スタブの `$scope` を渡してテストしている。
- 必要に応じて Jasmine のスパイ機能とかを使えばいい気がする。

#コントローラとかを個別の関数として定義していない場合
```text:フォルダ構成
|-test.html      : テストを動かすための html.
|-app.js         : AngularJS の設定をしている js. コントローラの定義もまとめている.
|-test.js        : Jasmine のテストコード.
|-jasmine/       : Jasmine のファイル類.
`-angular/       : AngularJS のファイル類.
```

```js:app.js
angular
.module('mine', [])
.controller('SampleController', function($scope) {
    $scope.message = 'Hello SampleController!!';
  
    $scope.click = function() {
        $scope.message = 'clicked';
    };
});
```

```js:test.js
describe('suite', function() {
    var controller, $scope;
  
    beforeEach(function() {
        module('mine');
      
        inject(function($rootScope, $controller) {
            $scope = $rootScope.$new();
          
            controller = $controller('SampleController', {
                $scope: $scope
            });
        });
    });
  
    it('spec', function() {
        expect($scope.message).toBe('Hello SampleController!!');
      
        $scope.click();
      
        expect($scope.message).toBe('clicked');
    });
});
```

```html:test.html
<!doctype html>
<html>
  <head>
    <link href="jasmine/jasmine.css" rel="stylesheet"/>
    <script src="jasmine/jasmine.js"></script>
    <script src="jasmine/jasmine-html.js"></script>
    <script src="jasmine/boot.js"></script>
    <script src="jasmine/console.js"></script>
    
    <script src="angular/angular.min.js"></script>
    <script src="angular/angular-mocks.js"></script>
    
    <script src="app.js"></script>
    <script src="test.js"></script>
  </head>
  <body>
  </body>
</html>
```

- `angular.module().controller()` を使って匿名関数でコントローラを定義しているケース。
- mine モジュールからコントローラを取得する必要がある。
- `angular-mocks.js` を使うことで、テストコード中でモジュール内の各インスタンスを取得できる。
- `module('mine');` で、 mine モジュールを読み込んでいる。
- `inject()` に渡した関数内で必要なスコープやコントローラを取り出している。

#参考
- [AngularJS で Hello World - パンダのメモ帳](http://shogogg.hatenablog.jp/entry/2013/01/25/005753)
- [angular.mock.module | AngularJS 1.2 日本語リファレンス | js STUDIO](http://js.studio-kingdom.com/angularjs/ngmock_global_apis/angular_mock_module)
- [Unit Testing Best Practices in AngularJS](http://andyshora.com/unit-testing-best-practices-angularjs.html)