はじめに
AngularJSはとても便利なフレームワークですが慣れるまではなかなかに時間がかかります。その上Jasmineを用いてテストを書こうとすると「これはAngularJSの記述なの?Jasmineの記述なの?」と混乱することが私は多々ありました。
今回はごく簡単なAngularJSのサービスをJasmineを用いてテストファーストで構築していく過程を例示してそのあたりを整理したいと思います。なお、理解を簡単にするために厳密な説明は行っていません。これをきっかけに雰囲気を掴んでいただいて詳細は皆さん各自で深堀りしていただければと思います。
開発プロセス例
1. 設計
名前を引数として与えると ‘Hello 名前’ という文字列を返すメソッドsay(name)
を持ったHelloService
サービスを作ってみます。このサービスは MyServices
というモジュールに入れることにしましょう。
2. 実装
ではさっそくこの振舞をテストコードに落としこむことから始めてみます。
1. テストスイートの宣言
describe
関数はひとまとまりのテストスイートを宣言します。Jasmine
の記述です。
// helloSpec.js
+ describe('テスト', function() {
+ });
2. テストケースの宣言
it
関数はひとまとまりのテストケースを宣言します。Jasmine
の記述です。
// helloSpec.js
describe('テスト', function() {
+ it('HelloService のテスト', function() {
+ });
});
3. テスト対象のサービスをロード
beforeEach
関数はあるテスト単位前に必ず実行される処理です。Jasmine
の記述です。
module
関数はangularモジュールをロードするための宣言です。angular.mock.module
の記述です。ここではテスト対象のHelloService
が入っているMyServices
モジュールをロードしています。
inject
はサービスの参照を解決します。angular.mock.inject
の記述です。ここではHelloService
サービスの参照を解決します。
// helloSpec.js
describe('テスト', function() {
+ beforeEach(function() {
+ module('MyServices');
+ });
- it('HelloService のテスト', function() {
- });
+ it('HelloService のテスト', inject(function(HelloService) {
+ }));
});
ここで以下のようなメッセージが表示されテストが失敗しました。MyServices
モジュールなんてないよ、と言われます。さっそく実装しましょう。
Error: [$injector:modulerr] Failed to instantiate module MyServices due to: Error: [$injector:nomod] Module 'MyServices' is not available!
4. サービスを実装
モジュールを定義します。
// myServices.js
+ angular.module('MyServices', [])
+ ;
今度は以下のようにHelloServiceProvider
なんて知らないよと言われます。
Error: [$injector:unpr] Unknown provider: HelloServiceProvider <- HelloService
サービスを定義します。
// myServices.js
angular.module('MyServices', [])
+ .service('HelloService', function() {})
;
テストが通りました。対象サービスを実装してロードできましたね。
5. メソッドのテストを宣言
expect
, toEqual
関数はJasmine
の記述です。
ここにあたる部分をコーディングする頻度が最も高くなると思います。もちろんtoEqual
だけでなく様々な判定用メソッドが存在します。
// helloSpec.js
describe('MyServicesのテスト', function() {
beforeEach(function() {
module('MyServices');
});
it('HelloService のテスト', inject(function(HelloService) {
+ expect(HelloService.say('Quartet')).toEqual('Hello Quartet');
}));
});
ここで以下のようなメッセージが表示されテストが失敗しました。
TypeError: undefined is not a function
6. メソッドの実装
// myServices.js
angular.module('MyServices', [])
.service('HelloService', function() {
+ this.say = function (name) {
+ return 'Hello ' + name;
+ };
})
;
これで無事にテストが通りました。実装完了です。
最後に
今回はごく簡単なサービスで例示しました。これだけの記法をわかっているだけで基本的なテストは記述できるのではないでしょうか。
しかしAngularJSの特徴であるDIを駆使したサービスのテストには至っていません。そこで次回は依存サービスがある場合の記述について記したいと思います。
ちなみに当エントリのコードはこちらにありますのでご参考まで。
http://plnkr.co/edit/zQ6pj0