Android Test Test Test
Androidで案件やってるとテスト用、本番用の設定が多々必要になります。
Cでは#ifdefとかでコードを除外でき、リバースエンジニアリングもされにくい。でもAndroidは怖いです。プリプロセッサのディレクティブが使えないのですべてソースコードに含まれます。
Javaなので仕方ないのですが逆コンパイルも簡単にできちゃいます☆(ゝω・)vキャピ
こんなのでリリースできねぇ!開発サーバーの攻撃とか休日返上になってしまう!
というわけで対処します。
- ソースコードで分岐
なんかもう色々と気にしない潔い人用。わかちこわかちこ
if (BuildConfig.DEBUG)の嵐。 - 設定ファイルを差し替える
設定ファイルは差し替えればいいよ!リリースビルド前に設定差し替え!いつの日か差し替え忘れで・・・αβοοη..._φ(゚∀゚ )アヒャ - 設定ファイルを差し替えるその2
設定ファイルは差し替えればいいよ!adbで直接突っ込もう!プログラマしかいじれないブラックボックス。root端末しかダメだし、ダメダメ - 設定ファイルを差し替えるその3
BuildConfig.DEBUGでprefs.xml、prefs_test.xmlとか読み分ければいいね!
これもapkに含まれても気にしない潔い人用。 - プロジェクトを分ける
ifdefがないならプロジェクトを分ければいいじゃない。(まりーあんt
prefs.xml以外マージしていけばめんどいけどそれなりじゃね?マージし忘れてコンフリクトとか楽しい!!!真っ赤に燃えた競合だから♪ - 別アプリを作る
別アプリの設定をBuildConfig.DEBUG見て読めばいいじゃん!
別アプリがなければ設定読めなくて例外が発生するから、別アプリのインストール必須でふとした拍子の本番設定とかも防げる!
リリース時はフラグが降りるから当然自分のアプリの設定が読まれるよ!
いけてる方法。イケメソ。それは・・・別アプリを作る!
結構大それたように感じるし、上司からも怪訝な顔されることうけあい。もうセキュリティとかいいじゃんみたいなことに。
でも簡単なんです。SharedPreferencesで設定を読むだけ!
まあググればすぐに出るんですけど
createPackageContext(CONTEXT_IGNORE_SECURITY)
getPreferences(MODE_WORLD_READABLE|MODE_WORLD_WRITABLE)
みたいなやつです。テスト設定アプリはPreferenceActivityとかで軽く作れちゃうし。
ただし注意があります。ここからなぜかあまり情報がないので書いておきますがテストアプリと、本番アプリで設定ファイル名を変えておく必要があります。
設定ファイル名が同じだとひっそりとキャッシュされたSharedPreferencesのインスタンスが返ります。これにはなんだかとてもはまった。
明らかにテストアプリのコンテキストから取得してるのにデバッグログを見て絶望。
調べたら/(^o^)\ナンテコッタイ
設定の書き込みは本番にとかコンテキストを使い分けてやっていたからそのタイミングで先にキャッシュされてしまっていたのでしょう。
次に注意すべき点。
自身のコンテキストではないSharedPreferencesへの書き込みはミスります。
Couldn't rename file *** to backup file ***みたいなログが出る。
試しにchmodでパーミッション変えるとうまくいく。なんだよMODE_WORLD_WRITABLEって!!!ワールドイズマインじゃねえか!!!
というわけでandroid:sharedUserIdを使いましょう。
まあSharedPreferencesが楽だからこんな感じです。別アプリのデータ共有って意味ではContentProviderを使うのがベストプラクティスみたいな。
暇があればサンプルコードでも置いときます。
AIDE (Android Java IDE) JUnit Test Tutorial part2
前回に引き続き、JUnit。
さすがにあのやり方はだるすぎます・・・
せめて、Terminal Emulatorを使わずにやってみます。
package com.mycompany.myapptest; import android.app.*; import android.os.*; import android.widget.*; import java.io.*; import java.lang.Process; import android.view.*; public class MainActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); getDefaultTextView().setText(executeTest()); } private String executeTest() { String result = ""; try { ProcessBuilder pb = new ProcessBuilder( "am", "instrument", "-w", "-e", "class", "com.mycompany.myapptest.HelloTest", "com.mycompany.myapptest/android.test.InstrumentationTestRunner"); Process p = pb.start(); InputStream input = p.getInputStream(); byte[] buffer = new byte[1024 * 4]; int readBytes = 0; StringBuilder sb = new StringBuilder(); while ((readBytes = input.read(buffer)) > 0) { sb.append(new String(buffer, 0, readBytes)); } result = sb.toString(); } catch (IOException e) { e.printStackTrace(); } return result; } private TextView getDefaultTextView() { ViewGroup root = (ViewGroup)findViewById(android.R.id.content); LinearLayout main = (LinearLayout)root.getChildAt(0); TextView textView = (TextView)main.getChildAt(0); return textView; } }
こんな感じ。
Yeah!
できました!
AIDE (Android Java IDE) JUnit Test Tutorial
素晴らしい、Android Java IDE。
https://play.google.com/store/apps/details?id=com.aide.ui&hl=ja
開発ぐぐたす
https://plus.google.com/101304250883271700981/posts
今回、ユニットテストをAndroid端末単体で行ってみます。
TerminalEmulatorをインストールする必要があります。
きっとこのアプリ使う人は入ってると思うので説明は省略します。
自分の環境はACER ICONIA TAB A100, Honeycomb 3.2で実行しています。
1. メインプロジェクトを作成
ここではデフォルトのMyAppとします。
AppName: MyApp
Package Name: com.mycompany.myapp
2. テストプロジェクトを作成
AppName: MyAppTest
Package Name: com.mycompany.myapptest
3.テストプロジェクト設定
テストプロジェクトのAndroidManifest.xmlを編集します。
以下のコードを追加していきます。
どこでもいいと思いますがuses-sdk要素の後ろに書きます。
<instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.mycompany.myapp" />
次にapplication要素の中に
<uses-library android:name="android.test.runner" />
を書きます。
4.テストコード作成
次に/mnt/sdcard/AppProjects/MyAppTest/src/com/mycompany/myapptest以下に
HelloTest.javaを作成します。
テストを先に作ったのでHelloとかエラーですがとりあえず保存します。
5. テストプロジェクト設定2
/mnt/sdcard/AppProjectsに戻り
MyAppディレクトリを長押ししてメニューからAdd library to projectを選択します。
MyAppTestからMyAppプロジェクトが参照されます。
6. コード作成
MyAppプロジェクトを開きます。
Hello.javaを作成します。
この状態でRunします。インストールします。
でも実行はしません。Activityが立ち上がるだけです。
7. テストプロジェクトインストール
再度MyAppTestプロジェクトを開きます。
HelloTest.javaを開きます。
やったね!先ほどのエラーが出てません!当たり前ですね。。。
この状態でRunします。インストールします。
でも実行はしません。Activityが立ち上がるだけです。
6. テストコマンド実行
TerminalEmulatorを立ち上げます。
立ち上がったらamコマンドを実行してみます。
テストに使用するコマンドです。
詳細は以下のドキュメントを参照してください。
http://developer.android.com/reference/android/test/InstrumentationTestRunner.html
以下のコマンドを実行します。
am instrument -w -e class com.mycompany.myapptest.HelloTest com.mycompany.myapptest/android.test.InstrumentationTestRunner
テストで失敗しています。 Hello Hogepiyoが期待されていたのですが、Helloしか返していないからです。
8. コード修正
AIDEに戻ってコードを修正します。
MyAppプロジェクトを開き、Hello.javaを編集します。
"Hello"を"Hello Hogepiyo"と修正します。
Runします。インストールします。
実行しません。
9. 再度テストコマンド実行
テスト成功しました!!!ヒャッハー!!!!!!!!!!!
Android端末単体でここまでできるのは素晴らしいことです。
ですが、さすがに一苦労ですね。
次回は若干ステップを減らす方法を書きたいと思います。