AIR(HTML+JavaScript)アプリケーションをQUnitでテストしてみる

http://d.hatena.ne.jp/xibbar/20120327#1332854876

本日の朝活でもJavaScriptというかAIRアプリケーションを書いてました。
朝活参加者は5名。
皆様お疲れ様でした。


で、HTMLベースのAIRアプリケーション開発でテストを実行する方法について。
他にもっと良い方法があったら教えてください。
ちなみにActionScriptベースのAIRなら、FlexUnit使えばいいです。

前提


AIR SDK部分、例えばファイル読み込み、書き込み等がテスト出来ないといけないので、AIRランタイム上での動作環境でないといけない。
AIRのHTMLレンダリングエンジンはWebKit相当なので、クロスブラウザは考慮する必要が無い。
JavaScriptなのでJavaScript用のテストツールがいい。
テスト実行してもアプリの環境に影響がないように、テスト環境は切り分けたい。

検討


1.JsTestDriver
クロスブラウザ対応する必要無いのでパス


2.JsUnit
QUnitの方が主流なようなので?パス


3.FlexUnit
AIRのHTML環境では、ActionScriptのライブラリを読み込めるようにscriptタグが拡張されています。

<script src="lib/myClasses.swf" type="application/x-shockwave-flash"></script>

これを利用すればFlexUnitも使えますが、HTMLベースのAIRの場合、わざわざやるメリットがないかと。
よって今回はパス。


4.QUnit
最近の主流はやはりこれでしょうか。今回はこれを採用します。

QUnitをダウンロード


以下からダウンロードします。
http://docs.jquery.com/Downloading_jQuery
CDNで外部から読み込んでも可。

AIRアプリケーションを準備


実際にやってみます。
ローカルファイルを読み込み、その内容をdivタグに表示するというケースを例にとってみます。
動作イメージは以下の通り。

ボタンをクリックすると

読み込んだファイルの中身を表示


テスト対象のAIRアプリケーションをまずは普通に作成します。

メインのHTML,アプリケーション記述ファイル,AIRAliases.jsを適当に用意。

<input type="button" id="button" value="Read a local file using AIR APIs">
<div id="divE"></div>

メインのHTMLにファイル読み込み用のボタンと、表示用のdviエレメントを用意。


追記:ロジックをテストするだけだったので、ボタンとdivエレメントは、今回のテストには関係ない部分でした。

<script>
  var divE=document.getElementById('divE');
  document.getElementById("button").addEventListener('click',function(e){
    var content=readLocalFile();
    divE.innerHTML=content;
  });
</script>

アプリケーション自体も動かすならメインのHTMLにこんな感じで追加してください。



ダウンロードしたQUnitを忘れずにプロジェクト内に突っ込んでおきます。

テスト環境を用意


今度はテストを用意します。

テスト用のHTMLファイルと、そのアプリケーション記述ファイルを作成します。
先ほど作成したHTMLとアプリケーション記述ファイル名は、上にTestを付けたものにしてみました。

  <link rel="stylesheet" href="lib/qunit/qunit.css"/>
  <script src="lib/qunit/qunit.js"></script>

テスト用のHTMLファイルで、QUnitJavaScriptCSSを読み込んでおきます。

あ、読み込み対象のファイルとロジックを記述するJavaScriptファイルを忘れていました。

追加します。LocalFile.txtとApplication.jsとしました。
ロジックを記述するjsの中身はまだ空でいいです。
読み込まれるファイルの中は適当に用意して下さい。

テストを記述するJavaScriptファイルを用意します。

 <script type="text/javascript" src="lib/AIRAliases.js"></script>
<script type="text/javascript" src="lib/Application.js"></script>
<script type="text/javascript" src="test/TestApplication.js"></script>
<div id="qunit"></div>
</body>

テスト用のHTMLファイルに、AIRAliases.js,ロジックファイル、テスト記述ファイルを読み込みます。また、テスト結果表示用エレメントも用意しておきます。

テストコードを書いてみる


準備が整ったのでtestApplication.jsにテストを記述していきます。

test('Local file read',function(){
  equal(readLocalFile(),'This is the content of the "LocalFile.txt"',"read complete");
});

readLocalFileというファイルの中身をStringとして取得する関数を読んで、実際に取得出来ているかという内容にしました。

adl TestAIRSample.xml

adlで起動してみます

readLocalFileという関数はまだ実装していないので、当然失敗します。

function readLocalFile(){
  var f = air.File.applicationDirectory.resolvePath("LocalFile.txt");

  var fs = new air.FileStream();
  fs.open(f, air.FileMode.READ);
  var content = fs.readUTFBytes(fs.bytesAvailable);
  fs.close();

  return content;
}

Application.jsにrealLocalFileを実装します。

adlで実行してみると、今度は成功しています。

まとめ


HTMLベースのAIRでのテストは、殆ど、というか全くといって良いほどWeb上に情報がなかったので、このような感じにしてみました。
ポイントは同一プロジェクト内にテストアプリケーションを置くことです。
このようにすると、アプリケーションのロジックをテスト側から簡単に呼ぶことができます。
今回の例では出てきていませんが、このようにするとアプリケーションの記憶領域*1はアプリケーションとテストで別々に用意されますので、記憶領域を使って読み書きするような場合、テスト環境がアプリケーション環境を汚さずに済みます。
又、アプリケーションが大規模になってきた場合には、テスト自体を分割して、複数のテストアプリケーションを用意すれば、各テスト環境が別々になりますので、setupやteadownの必要性が減ります。
悪くない手法ではないかなと考えています。

*1:OS Xの場合、/Users/exampleUser/Library/Preferences/com.example.exampleApp/Local\ Store/