目次
Node.jsとJasmineとKarmaでのモジュールテストの続き。
ここでは、複数のモジュールが連携している場合のテストと、モックの利用について説明する。
3つのモジュール、Product,Wallet,Bankがあり、それぞれ以下のような役割分担を持つ。
下に行くほど、上のモジュールに依存している。
単体テストを行う場合、対象となるモジュールが期待通りに動いていることを確認することが必要である。
例えば、Bankモジュールをテストする場合、Bankが提供する機能のうち、他のモジュールが行っていることではない機能についてテストする。他のモジュールの機能はそのモジュールの単体テストによってテストされるべきである。
モックとは「偽物」や「模造品」のことで、本物のふりをして本物らしく動作するけれども本物ではないものを意味する。
ちなみにモックの他に似たような言葉としてスタブ、フェイク、ダミーなどがあり、正確に言うとそれぞれで意味が異なるのだが、その辺の細かいことはここでは省略。
ここでは、テストスペックにモックを使用するためにrewireというモジュールを使用する。rewireモジュールはすでに前回のセミナーで、Node.jsのnpmによってインストール済み。(第4回参照)
どのような状況でモックが使用されるのか?
例えば、上記の3つのプログラムを3名の開発者が開発しており、まだProductとWalletは出来上がっていないが、Bankだけはもう完成してテストしたい、というような状況である。
この場合、ProductとWalletをモックにしてBankSpecに注入することにより、まだ実体のないProductとWalletに依存するBankをテスト可能となる。
rewireを使ったモックの注入手順は以下の通り。
Karmaとはブラウザベースのテスト環境で、通常はユーザが手作業で行わなければならない、テキスト欄に文字を入れたりボタンをクリックしたりして行うテストを自動化できる。
Karmaは様々なブラウザに対応しているが、ここではChromeだけを対象として検証する。
なお、Karmaと並んで有名なUIテスト環境としてSeleniumがある。
Karmaのインストールも前回に済ませてある。
前回のインストール時に、
>karma init
を実行してプロジェクトルートフォルダにkarma.conf.jsというファイルを作ってあるが、それに次の設定を追加する。
module.exports = function (config) {
config.set({
…
files: [
'*.html', // ←ここ
'src/*.js',
'spec/*.js'
],
…
preprocessors: {
'*.html': 'html2js' // ←ここ
},
…
});
};
最初の設定はテスト対象として.htmlファイルも含むようにする。
2つ目の設定は.htmlファイルを読むときhtml2jsという前処理を行うようにする。karma-html2js-preprocessorというモジュールも前回インストール済みである。
ブラウザテストを行うには、通常のウェブアプリと同様にHTMLファイルをJavascriptファイルが必要となる。
Karmaでテストを行う場合は、テストファイルの中にrequire()を書く必要はない。karma.conf.jsの中の['src/*.js','spec/*.js']で相互参照が行われるからである。
また、テストコードの最初で、html2jsを使用してHTMLをJavascriptとして扱えるようにしている。これにより、DOMツリーが使用できる。
Karmaを使ったテストは以下のように実行する。
karma start karma.conf.js
これで、設定ファイルに従って自動的にブラウザが起動し、テストが実行される。
ディレクティブとは、HTML命令を拡張する機能である。
AngularJSには、最初から多くのディレクティブが準備されており、それを組み合わせて使うことでほとんどの処理は実現できる。
したがって、あまり独自のディレクティブを作らなければならないような場面は少ないと思うが、ここでは例としてディレクティブの作成について説明する。
独自のディレクティブは以下のような構文で宣言する。
var app=angular.module("App");
app.directive("DirectiveName",function(){
return {
// ここに、必要なディレクティブの設定項目を書く
};
});
設定項目には以下のものがある。
| 項目名 | 意味 |
|---|---|
| restrict | このディレクティブの使われ方。要素(E)、属性(A)、クラス(C)、およびコメント(M)を組み合わせて文字列で指定する。デフォルトは'EA'である。 |
| priority | 同じ要素で指定されているディレクティブの優先順位を決める数値。デフォルトは0。 |
| template | インラインのテンプレート文字列。この文字列がHTMLとして使用される。 |
| templateUrl | テンプレートとして使う文字列が入っているURL。長い場合はこちらが良い。 |
| replace | trueならばもとのHTMLがディレクティブのHTMLで置き換わる。falseならば挿入される。デフォルトはfalse。 |
| transclude | trueの場合、元のHTMLの子要素がディレクティブのHTMLのng-transcludeで指定されている要素へと移される。 |
| scope | 親の$scopeを継承せずに、このディレクティブのために新しい$scopeを生成する。 |
| controller | ディレクティブ間での通信を可能にするコントローラを生成する。 |
| require | このディレクティブが正しく機能するために必要な他のディレクティブを指定する。 |
| link | ディレクティブが生成された後で、DOMを変更したりイベントリスナーを追加したりデータバインディングを定義したりする。 |
| compile | ディレクティブが生成される際に1回だけ呼び出される処理を記述する。$scopeは利用できない。link関数を返すこともできる。 |
AngularJSを使ったウェブアプリの開発の課題である。
数字が大きくなるにつれて複雑になるので、まずは1から順にこなしていってほしい。