Androidでレガシーコードを書き続けないためのたった1つの方法
答え:テストできるように作る
周りでAndroid開発してる話を聞くのですが、どうもテストがしづらかったり、修正が大変だったりする模様。ここを直してあそこがバグるみたいな。
本屋で参考になりそうな本を探すも、入門系かリファレンス系が殆どで、「どういう設計にするべきか?」とか「Android Test」とかAndroid向けフレームワークの話がさっぱり無い。そんな状況なので、入門書片手にアプリを書き始めた人は、ViewとLogicを始め、色々なものが適切に分けられてないコードを作り、テストの無いレガシーコードが量産されていくのかな、と。
そういう分けで最初の結論になります。
ちょうど、ちょっとしたAndroidアプリを書いてみようと思ってたので、ここら辺を参考に実際のアプリに先立っていくつかのフレームワークを組み合わせたAndroid-Development-Suiteを作成。
いわゆるサンプルアプリですねw
これをcloneするなり何なりして使えば、テストがある状態、書ける状態から戦いを挑めるはず><
既存コードにテストを入れるときの参考にも一応なるはず。
https://github.com/koduki/Android-Development-Suite
内容的には、まずはビルド基盤としてmavenを導入。
どうもEclipse上で全部やるのがトレンドな気はしますが、CIはじめ自動化を考えるならビルドツールは必須ですよね。というかIDE完結とか自動化する気無いだろ...
ant + ivyやgradleとかも悩みましたが、機能とよく使われてるという点を考慮してmavenを選択。
通常ビルドやテストはもちろん、Androidへのデプロイやリリース用にproguradや署名かけることも可能です。
リリースビルドに署名をするときのkeystoreやパスワードは、直接pom.xmlではなく、~/.m2/settings.xmlに書くようにしています。てか、ここに独自程度のプロパティ書けたんですね。知らなかったです。便利。
また、JDK7から、keytoolの仕様が変わってしまい、Androidと互換性のある署名を作れないので、JDK6から実施するようにしてください。
Eclipseのみの開発でテスト用とリリース用でコードを直接書き換えてたあなたもこれで幸せになれますね!
ただ、一部、私のmaven力が足らなくて、シェルにしてしまったので、誰か教えてください>< もしくはpull request大歓迎!
次に入れたのがandroid-binding。こいつはAndroidでMVVM(MVP)モデルを実現するためのもの。古典的なMVCモデルやWebでお馴染みのMVC Model2だと、プレゼンテーションロジックをどこに書くかいつも悩むので、MVVMでやって見ることに。まあ、マイクロソフトとかが前からやってる感じのやつですね。これでActivityがごちゃごちゃさせずに、POJOでテスト出来るところが増えるはず! ViewModelはPOJOですので。
土台系としてはDIも導入。Google GuiceのAndroid版のroboguice。ネットワーク周りとか副作用のあるテストをモックに切り替えるのが目的。しかし、設定ファイルじゃないので、ビルドオプションで簡単に実装変えるわけにもいかず、結果変な実装に。この辺はもっと良い方法を考えないと。
DIを入れたからにはMockツールもということでMockitoを入れました。EasyMockベースのAndroidMockというのもありますが、Mockitoも最新版はAndroid対応なので、評判のよさげなMockitoに。
なにげにこの手のツールを初めて使ったんですけど、かなり便利。ネットワーク系をラップできるのは強力なので、他のところにもどんどん入れてこうと思います。
ちなみに、サンプルで作ったテストケースが少し無理矢理というか、ふつうにUnitTestを書けば十分なのは、まあ、サンプルという事でw
で、最後に実機やエミュレータに対する結合テスト用にCabash-Android。
最初はSelenium(NativeDriver)を使おうとしてたんですけど、結構めんどくさかったので、他のを探して見ることに。そしたらなんとCucumberが使えるじゃないですか、奥さん!
というわけで、迷わず導入。NativeDriverより導入するのも記述するのも簡単だし、スクリーンショットも取れるのでいうことなしですね! まだ、できない操作があるかまでは確認できてないけど、その辺は使いながらおいおい。
Cucumberなので、テストケースをそのままテスト仕様書としても使用可能なのがGoodです。
あと、もちろんmavenを使ってるのでプロファイルで、いくつか環境を切り分けれるようにしています。
mockをインクルードするdevelopmentプロファイル、mockを使わないproductionプロファイル、Proguard等をかけるreleaseプロファイル。resourcesディレクトリをprofileに対して別にしてるので、環境依存とかはここに吸収する感じで。
これで、CIで回すと、ひたすらツイートされ続けるという残念な状況も解決です。
と、こんな感じで、Webアプリ作るならこの辺入れるだろー、というのと同程度のものを導入して覽ました。ORMはまだ入れてないので、なんか入れようとは思います。Android初心者の私が作ったものなので、色々考慮不足が有りそうですが、これをベースにアプリを作ってFB を重ねていきたいですねー。
参考:
- Android開発で泣かないための「テスト」の重要性
- [Android]android-maven-pluginでリリース用APKをビルド
- 双方向Bindingが可能なAndroid Binding v0.45を使ってみた
- 開発者が知っておくべき、6つのUIアーキテクチャ・パターン
- 「レガシーコード改善ガイド」のススメ