angular.jsのチュートリアルにはテストもきちんと含まれているが、キューピー3分間クッキングなみに出来上がった状態で提示されてくる。そのため、なんとなくわかった気になるが実際よく分かっていないという状態に陥りがちである。
どうなっているかをすこしは理解したいと思い、angular.jsでのテスト環境を一から構築してみる。
ユニットテスト Karma
ユニットテストはKarmaを使うのが楽そうである。公式のチュートリアルなどもKarmaが前提になっている。まあ、Karma自体が「angularのために」からスタートしているので相性がいい、かつ情報が豊富なのは当然なので使わない手はないと思う。
ここでは、Karma・mocha・chaiの構成を取る。基本的な設定は以前のポストをご参考頂ければ。CLIが分離したKarma0.12でmocha,chaiの環境を整える | niwaringo() {Tumblr}
angular.js特有の注意点は以下。
angular-mocks.jsのインストール
依存解決等のためにangular-mocks.jsが必要になる。bowerなどを使って事前にインストールしておく。
$ bower install angular-mocks -D
karma.conf.jsの注意点
angular.jsを一番最初に読み込む
bower_components以下全てのJSファイル読み込みなどとしておくと、angularが読み込む前にangular-mocksが読み込まれてエラーになるという悲しい自体に遭遇したりする。そのため一番はじめにangular.jsを読み込んでおく。
files: [
'bower_components/angular/angular.js',
'bower_components/**/*.js',
'app/js/*.js',
'test/unit/**/*_spec.js'
],
minファイルの除外
ちなみにbowerでインストールした場合は、minファイルも一緒にインストールされる事が多いためminファイルは除外しておくと良さそうである。angular特有ではないが、、、、
exclude: [
'bower_components/**/*.min.js'
],
テストファイルでの注意点
angularはDIが非常に特徴的である。テストの時にコレを解決するためにmoduleでテストしたいモジュールを呼び出して、injectを使って依存を解決するという形を取る。module
、inject
はangular-mocksがグローバルに追加される。
describe('PhoneListCtrl', function(){
beforeEach(module('phonecatApp'));
it('should create "phones" model with 3 phones', inject(function($controller) {
var scope = {},
ctrl = $controller('PhoneListCtrl', {$scope:scope});
expect(scope.phones).to.have.length(3);
}));
});
上記テストコードはチュートリアルで紹介されているコード。(expectはchaiにしていますが)
ユニットテストはangular-mocksを使って依存を解決すれば基本問題はなさそうである。angular-mocksは他にも色々便利そうなのできちんと調べたほうが良さそう……そのうち。
E2Eテスト {protractor}
E2Eテストは、angular.jsのために開発された「protractor」というテストフレームワークがある。昔はKarma自体にE2Eの仕組みが組み込まれていたが分離されて、ユニットテストはKarma、E2Eテストはprotractorという役割分担になっているようである。protractorは現在かなり活発に開発が進められているので「あれ?」と思ったらアップデートすると解決することが多い :P
protractorのインストール
公式ではグローバルになっているが、とりあえずはローカルで様子見を。
$ npm install protractor -D
standalone selenium server と chromedriverのダウンロード
protractorはWebDriverJS
が土台になっているため、seleniumのstandalone severが必要になる。(chromeだけでテストする場合はchromedriverだけでも良い)
以下のコマンドでselenium-server-standaloneとchromedriverの両方をダウンロードしてくれる。
./node_modules/protractor/bin/webdriver-manager update
設定ファイルの作成
protractorは、Karma同様に設定ファイルを指定してテストを実行する。そのためひな形をコピーして設定ファイルを作成する。
cp ./node_modules/protractor/referenceConf.js referenceConf.js
設定ファイルにはかなり丁寧なコメントが書かれている。何点かピックアップしてみると、
- クロムだけでテストするならchromeDriverだけでseleniumSeverJarは指定しなくてもよい
- SauceLabsがサポートされている
- テストのための引数とかも設定可能
--params.login.user 'Joe'
- Mochaはベータサポート :(
mocha, chaiを使うための設定
ベータ版のようだが、基本的にはmocha・chaiが使える。
mocha, chai, chai-as-promisedのインストール
mochaはグローバルでのインストールが必要っぽい。あと、protractorはpromiseが各所で使われているのでchai-as-promisedが推奨されている。
npm install -g mocha
npm install chai
npm install chai-as-promised
設定ファイルの変更
設定ファイルのframework
をmochaにする。デフォルトはjasmine。確かKarma自体にE2Eが合った時はオレオレ仕様だったので一般的なフレームワークが使えるのはかなりありがたい。
framework: 'mocha',
mochaのオプションを設定
mochaOpts: {
ui: 'bdd',
reporter: 'spec'
},
reporterをspecにしておいた(デフォルトはlist)
テストファイル
公式で紹介されているプラスαでこんな形になる。
/*jshint -W079 */
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
var expect = chai.expect;
describe('angularjs homepage', function() {
it('should greet the named user', function() {
browser.get('http://www.angularjs.org');
element(by.model('yourName')).sendKeys('Julie');
var greeting = element(by.binding('yourName'));
expect(greeting.getText()).to.eventually.equal('Hello Julie!');
});
});
chai, chai-as-promisedを読み込んで設定しておき、expectをchaiのものに上書きをしておく。なお、jshintを使っている場合はexpectの上書きは警告がでるとおもうので、冒頭で無視するように/*jshint -W079 */
を記述しておく。
expectはeventuallyを挟んでpromiseに対応しておく。
- protractor/docs/using-mocha.md at master · angular/protractor
- JSLint Error Explanations - Redefinition of ’{a}’
* * *
angular.js自体が非常に大きなライブラリで様々な物を含んでいるが、エコシステムとしてテスト環境も整備されている。好みの問題だが身を委ねてしまうと非常に楽になる。