iOSアプリのインテグレーションテストに関する問題

iOSにかぎらず、今日のアプリケーションではサーバとクライアントの両方を開発しなくてはいけないことが、決して特別ではありません。その際にややこしいのが次のような事情です。

  • 開発は同時に行われるので、厳密にプロトコルを予め決めておいて、モックだけでテストして幸せになれるわけではない*1
  • クライアントとサーバは別々の言語で開発されることが多いが、テストしたいのは両方の状態の整合性である

1つ目の問題は、まあ手抜きと言えばそうなんですが、サーバもクライアントも一人で開発していると、万が一なにかのトラブルがあったときに「定義されているプロトコルにそって開発しているのだから、これはクライアント|サーバのバグである。俺は悪くない!」とか、全く言えないわけです*2。ちゃんとend-to-endで動くことを確かめましょう。

じゃあ、テストしたいと思っても、2番目の問題が浮上してきます。


サーバはRailsで書いているんだけど、クライアントはObjective-C、とか、なんでも良いんですけど、それぞれ別の言語で開発されていることは全く稀ではありません。これ、結構辛い問題です。

iOSアプリの操作を自動化すること自体は、UIAutomationという仕組みで簡単にできます。実は、アプリをぽちぽちと適当に操作して、その操作を記録したJSを作ってくれるので、それを実行すると、「じゃあ今日は300件、会計を入力してね♪」とか弊社でインターンの子を凍りつかせたことがある指示を出したことがあるのですが(恥ずかしながら:これは恥です)、そういうことはなくなります。一回操作してJSを作り、forでループすれば良いのです。KIFなどのテスト用のフレームワークも公開されており、iOSアプリ内部で完結するようなテストは、かなり環境が整ってきています。

ところが、話はそんな簡単ではない。なんかのサーバと連携するアプリをテストするとしましょう。まずサーバの環境をリセットして、それからサービスにサインアップして、サーバの設定をして、アプリが走って、なにか通信をして、その結果のサーバの状態を確認したい。どうやってクライアントのテストからサーバの環境をリセットすれば良いのでしょう?サインアップは?最後にサーバの状況を確認するのはどうすれば良い?力技としては、サーバに環境リセット用のAPIを用意して、環境の情報を取得するためのAPIを用意して、それらを用いてテストを行う、ということになります。が、まあ、とても面倒くさい。

どうしたものでしょう。


ちょっと視点を変えて、RailsのWebサイトでインテグレーションテストがどのように行われているかを見てみましょう。

Railsのインテグレーションテストでは、ブラウザーRubyのテストプログラムから操作するということが広く行われています。Seleniumを使って実際のWebブラウザを操作することもありますし、capybara-webkitなどのテスト専用のブラウザを使用することも広く行われています(ちなみに私はcapybara-webkitでテストをやっています)。

同じようにやれば良いのではないでしょうか?


iOSアプリをRubyから操作して、テストを実行します。テストプログラムにはRailsの環境をロードしておけば、テスト中の環境の変更を内側からテストできるようになるわけです。


そこで調べてみると、Frankというプロジェクトがあることを知りました*3。(惜しむらくはCucumberが前提っぽいところなのですが、)これ……、いいじゃん!



続きます。

*1:いやもちろんユニットテストのレベルとかではモックで良いと思うのですが、近代的なソフトウェア開発においては、やっぱりちゃんとインテグレーションテストするようにして、うっかりサーバの変更でクライアントがクラッシュするようなことがないようにしないといけないのです

*2:もちろん、プロトコルの定義に対して正しく実装していたから、責任がないとはならないでしょうけど。

*3:世の中に無いようだったら、自分で実装する覚悟を決めたところでした。が必要なかった。