ikeike443のブログ

ソフトウェアビジネスに関心がある系のブログ

Titanium Mobile + Jasmine + Jenkins でiPhoneアプリの自動テスト組んでみたよ

Jenkins Advent Calendar jp 2011の3日目です。


Titanium Mobile + Jasmine + Jenkins でiPhoneアプリの自動テスト組んでみた、っちゅう話をします。


本当はプラグインを作りたかったんですが、そこまで行かなかったので(言い訳だよ!)、せめて自動テストをどう組んだかの話をしますね。


Titaniumの自動テストを組みたい

最近Titanium Mobileを使ってiPhoneアプリなど作ってます。
f:id:ikeike443:20111202213606p:image
Titanium Mobileについてはもう説明もいらないと思いますが、Javascriptを使ってスマートフォンアプリ(特にiPhoneandroid)を開発することができるプラットフォームですね。


で、Jenkins野郎な私としては、Titaniumでも自動テストを組みたいんですよね。
Javascriptでテストってどう書くんだろう。


ふむふむ、色々あるね。


TitaniumにもDrillbitっていう組み込みのテストフレームワークがあるらしい。
http://developer.appcelerator.com/doc/mobile/drillbit
http://wiki.appcelerator.org/display/guides/Writing+Unit+Tests+with+Drillbit

でも、なんか動かないって言ってる人多いし、もうすこしメジャーっぽいテストフレームワークのほうがいいな。。
node.jsのテストも書かないといけないので、同じフレームワークを使えたほうがうれしいってのもあるし。


Jasmine可愛い

Jasmine
個人的にはこっちが本命。明確に RSpec-inspired.
Pivotal Labs がメンテナンスをしている。実はこれすごく重要。なぜなら JsUnit も pivotal/js-spec-server - GitHub も関係している Pivotal Labs があえて新しい JavaScript Testing Framework を作っているのだ。これが良くなくて一体何が良いのだ。
また、relevance/blue-ridge - GitHub というかなり気合いの入った Framework も今は「もうやらないから Jasmine 使え」って言ってるくらいなんだから、本命中の本命と言っていいと思う。
Pivotal Labs の名前を意識するようになったのはE和さんの中で流行っているという話を聞いてからだけど、jsUnit 自体は以前から知っていたので、これは正直期待しちゃうってもんだ。
http://aligach.net/diary/20101205.html

Jasmineよさそうじゃね。BDDってなんか濁点多くてカッコいいし、Pivotal Trackerも好きだし、よさそげ。


Jasmine
f:id:ikeike443:20111202212651p:image
花が可愛い。これにしよう。これにするよ!


jasmine-titaniumがあるよ!

既にjasmine-titaniumっていう素敵なものを書いてくれてる方がいました。ありがとうございます。
これでTitaniumをJasmineでテストすることができます。
でもこのままだと、テスト結果をコンソールに吐くか、
f:id:ikeike443:20111202213609p:image
iPhoneエミュレータで見るか、
f:id:ikeike443:20111202232709p:image
しかありません。
コンソールは見づらいし、iPhoneエミュレータは面白いけどCI向きじゃない。
さらに、エミュレータの場合、内部的にはWebViewを使ってHTMLを表示しているだけなせいか、requireが動かんのですよね。。そもそもテストが実行できないし!*1
もう一歩踏み込みたいです。やっぱりJenkins野郎としてはsurefireを吐かせてJenkinsにテスト結果を集計させたいですよね。


JasmineはReporterを別途定義してやることでテスト結果を差し替えられるので、surefireを吐くReporterを書いてやればいいよね。
っと思ってたら、jasmine.titanium.JUnitXmlReporter.jsってのが既にあったよ。すごいね世界って。
https://github.com/sgrimault/jasmine-titanium-reporters


jasmine-titaniumとjasmine.titanium.JUnitXmlReporterをつなげてみたよ

というわけで、つなげてみた。
https://github.com/ikeike443/jasmine-titanium


下記を修正した感じです。
https://github.com/ikeike443/jasmine-titanium/commit/dbde36696337a88ab074f039052916a6d5e7f86d

  • Reporterを足してオプションを増やしました。
  • libをTi.includeするのをやめました。specからrequireしてしまえばいいので。っていうかincludeすると名前空間が混ざってしまって困るです。
  • ライセンス関係の表記の仕方ってこれでいいんだっけ。。(プラグイン化するときにちゃんとします。。)


使い方は本家jasmine-titaniumとほぼ同じなんですが、ちょっとだけ違います。

まず、Titaniumのプロジェクトを作って、下記のようにして、vendor以下にjasmine-titaniumをcloneし、できたディレクトリの中に入って、.gitmodulesに定義されたsubmodule(jasmine自体とのリンクが貼ってある)のアップデートをします。

cd Resources
mkdir spec vendor
cd vendor
git clone https://github.com/ikeike443/jasmine-titanium.git
cd jasmine-titanium
git submodule init
git submodule update

次に、Titaniumプロジェクトのルートに.gitmodulesファイルを作り、下記のように保存します。要は、今度はアプリのプロジェクトとjasmine-titaniumのリンクを作るわけです。

[submodule "jasmine-titanium"]
        path=Resources/vendor/jasmine-titanium
        url=git://github.com/ikeike443/jasmine-titanium.git

テスト書くよ

さて、準備ができたのでテスト書きましょう。
テスト対象として、下記のようなコードがあったとします。

//db.js
(function() {
    exports.dbutil = function() {
        var self = this;
        self.dbName = 'hoge.db';
        self.getName = function(){
            return self.dbName;
        };
        self.open = function () {
            self.db = Titanium.Database.open(self.dbName);
        };

        self.close = function () {
            self.db.close();
        };
})();

こいつのテストをspec以下に書きます。

//db_spec.js
describe("db", function() {
  var db;
  var dbutil;
  beforeEach(function() {
        db = new (require('models/db').dbutil);
  });

  it("name should be hoge.db", function() {
    expect(db.getName()).toEqual('hoge.db');
  });
});

とりあえずDB名があってるかどうかのテストを書いて見ました。
jasmineのテストは書き方がわかりやすくていいですね。


さて、ここまでできたらJenkinsの設定をしましょうぜ!


Jenkinsの設定しましょうぜ!!

フリースタイルのジョブを作って、バージョン管理からGitを選択(Gitプラグインは入ってますよね!)。
f:id:ikeike443:20111202213610p:image
Gitじゃなくてももちろんいいんですが、今回はGit前提で話を進めます。


次に、ビルド「シェルの実行」を選んで下記を設定。

git submodule init
git submodule update
cd Resources/vendor/jasmine-titanium
git submodule init
git submodule update
cd ../../
python vendor/jasmine-titanium/script/specs.py -r jenkins

さっき作った.gitmodulesの設定をもとに、submoduleを更新してやってから、specs.pyを実行します。
なんかcdを繰り返しててダサいですが気にしない。


さあ実行ですよ! えぃ!
f:id:ikeike443:20111202213611p:image


iPhoneエミュレータが立ち上がったよ! うまく行ったっぽい!
f:id:ikeike443:20111202213612p:image



さて、テスト結果は集計できてるでしょうか。。
f:id:ikeike443:20111202231318p:image
おおっ


f:id:ikeike443:20111202231315p:image
おおおっ


f:id:ikeike443:20111202231316p:image
おおおおっっ


f:id:ikeike443:20111202231317p:image
おおー。出来てるじゃん!


まとめとお断り

というわけで、jasmine-titaniumとJenkinsを使ってiPhoneアプリのCI環境をちょろっと作って見ました。
プロビジョニングファイルのインストールとか、AppStoreへの申請とか、CIとして整備したいことはまだまだありますが、まずはテストを自動化することが出来ました。


尚、今回紹介したこの方法はまだ全然荒削りです。例えばエミュレータのプロセスをちゃんと殺してないので、自動テストの実行後、エミュレータは上がりっぱなしです。。(えー。。)
設定も色々面倒臭いので、もう少し時間をとって、プラグイン化するところまで行きたいなーと思います。


ともあれ、今回は、Titanium+Jasmine+JenkinsでiPhoneアプリを自動化するよ! の巻でした。


次のJenkins勉強会までにはプラグイン化してしましたいですね。本家本元の@masuidriveさんはRubyでTitanium-Jenkinsプラグインを書いてるという噂も聞くので、そっちの方がすごいものになってるとは思いますが。。


さて、明日は@linoさんです。Jenkins実践入門の作者ならではの話を期待してます!!

*1:ブラウザ上でTitaniumのrequireと同じ挙動をするrequireの実装があったら教えて欲しいです。。Require.jsはうまく行かなかった。。