Android、Java、Web系、Linux、マラソン等の備忘録

2012/12/13

Android Mockでテストしてみる( ;ω;)

0 件のコメント
試行錯誤も、次の一手が残っていれば挑戦してみようと思えるのですが、流石に万策尽きた感が出て諦めようと思っていたのですが、何とか動いたのでメモしておきます。


[環境]
  • Eclipse IDE for Java Developers Helios Service Release 2
  • OS : Windows 7
  • Android Development Tools 21.0.0.v201210310015-519525
・Android Mockを利用してHTTP通信をテストするには(1/3) - @IT
http://www.atmarkit.co.jp/fsmart/articles/androidtest05/01.html

こちらの有り難い記事。サーバへの通信とかを疑似サーバを立てないでテストしたいと思ってたので、コレコレ!という事でやってみたのですが、次のページの、

・Android Mockを利用してHTTP通信をテストするには(2/3) - @IT
http://www.atmarkit.co.jp/fsmart/articles/androidtest05/02.html

を何度も熟読してもエラーが出て前に進めませんでした( ;ω;)



[コンソール]
Test run failed: Instrumentation run failed due to 'java.lang.ClassNotFoundException'

[LogCat]
11-25 22:48:55.440: D/AndroidRuntime(848): Shutting down VM
11-25 22:48:55.440: W/dalvikvm(848): threadid=1: thread exiting with uncaught exception (group=0xb5131180)
11-25 22:48:55.440: E/AndroidRuntime(848): FATAL EXCEPTION: main
11-25 22:48:55.440: E/AndroidRuntime(848): java.lang.NoClassDefFoundError: com/google/android/testing/mocking/UsesMocks
11-25 22:48:55.440: E/AndroidRuntime(848):      at java.lang.reflect.Method.getAnnotation(Native Method)
11-25 22:48:55.440: E/AndroidRuntime(848):      at java.lang.reflect.Method.getAnnotation(Method.java:275)
11-25 22:48:55.440: E/AndroidRuntime(848):      at android.test.suitebuilder.TestMethod.getAnnotation(TestMethod.java:60)
11-25 22:48:55.440: E/AndroidRuntime(848):      at android.test.suitebuilder.annotation.HasMethodAnnotation.apply(HasMethodAnnotation.java:39)
11-25 22:48:55.440: E/AndroidRuntime(848):      at android.test.suitebuilder.annotation.HasMethodAnnotation.apply(HasMethodAnnotation.java:30)
11-25 22:48:55.440: E/AndroidRuntime(848):      at com.android.internal.util.Predicates$OrPredicate.apply(Predicates.java:106)
11-25 22:48:55.440: E/AndroidRuntime(848):      at android.test.suitebuilder.annotation.HasAnnotation.apply(HasAnnotation.java:42)
11-25 22:48:55.440: E/AndroidRuntime(848):      at android.test.suitebuilder.annotation.HasAnnotation.apply(HasAnnotation.java:31)
11-25 22:48:55.440: E/AndroidRuntime(848):      at com.android.internal.util.Predicates$NotPredicate.apply(Predicates.java:122)
11-25 22:48:55.440: E/AndroidRuntime(848):      at android.test.suitebuilder.TestSuiteBuilder.satisfiesAllPredicates(TestSuiteBuilder.java:253)
11-25 22:48:55.440: E/AndroidRuntime(848):      at android.test.suitebuilder.TestSuiteBuilder.build(TestSuiteBuilder.java:189)
11-25 22:48:55.440: E/AndroidRuntime(848):      at android.test.InstrumentationTestRunner.onCreate(InstrumentationTestRunner.java:371)
11-25 22:48:55.440: E/AndroidRuntime(848):      at android.app.ActivityThread.handleBindApplication(ActivityThread.java:3920)
11-25 22:48:55.440: E/AndroidRuntime(848):      at android.app.ActivityThread.access$1300(ActivityThread.java:123)
11-25 22:48:55.440: E/AndroidRuntime(848):      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1185)
11-25 22:48:55.440: E/AndroidRuntime(848):      at android.os.Handler.dispatchMessage(Handler.java:99)
11-25 22:48:55.440: E/AndroidRuntime(848):      at android.os.Looper.loop(Looper.java:137)
11-25 22:48:55.440: E/AndroidRuntime(848):      at android.app.ActivityThread.main(ActivityThread.java:4424)
11-25 22:48:55.440: E/AndroidRuntime(848):      at java.lang.reflect.Method.invokeNative(Native Method)
11-25 22:48:55.440: E/AndroidRuntime(848):      at java.lang.reflect.Method.invoke(Method.java:511)
11-25 22:48:55.440: E/AndroidRuntime(848):      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
11-25 22:48:55.440: E/AndroidRuntime(848):      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
11-25 22:48:55.440: E/AndroidRuntime(848):      at dalvik.system.NativeStart.main(Native Method)
11-25 22:48:55.440: E/AndroidRuntime(848): Caused by: java.lang.ClassNotFoundException: com.google.android.testing.mocking.UsesMocks
11-25 22:48:55.440: E/AndroidRuntime(848):      at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:61)
11-25 22:48:55.440: E/AndroidRuntime(848):      at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
11-25 22:48:55.440: E/AndroidRuntime(848):      at java.lang.ClassLoader.loadClass(ClassLoader.java:461)

java.lang.NoClassDefFoundError: com/google/android/testing/mocking/UsesMocks

 ↑
( ?ω?)。oO(・・何を言っているのだねきみは?)

これが何故出ているのかわかりませんでした。jarファイルもちゃんと入れてるし...そもそも、記事の通りにやってるし。記事のサンプルソースも公開されているので、eclipseに取り込んで実行しようとしたらEclipseが固まりました。何か間違えた....?

で、足りないものを発見!


僕のテストプロジェクトにはAndroid Dependenciesがないし、annotations.jarがないコイツだ!と、ググったらlibsフォルダにjarファイルを突っ込めばいいという事が判明。さっそく、libsフォルダを新規作成し、このサンプルソースのように3種類のjarファイルを突っ込んでだら、Android Dependenciesが自動作成!よし実行!

で、Eclipse固まりました....

3つも入れちゃいけないみたいで、
  • annotations.jar
  • AndroidMockRuntime.jar
だけで良いようです。めでたしめでたし。

ちなみに、annotations.jarはandroid-sdkディレクトリのtools > supportに入ってます。
あとは、動かない理由などは、AnnotationProcesor.logあたりを参照したりすると良いようです。今回は必要ありませんでしたが。

で、記事のサンプルソースですが、Eclipseに取り込むと
テストプロジェクト右クリック > Properties > Java Compiler > Annotation Processing > Factory PathにSUPPORT_LIBが入ってるのですが、


記事中で触れてないけど、これには何を入れればいいの...? まあsupport libというくらいなので、とりあえずandroid-support-v4.jarへのパスを指定しておきました。

動かす事に躍起になっててサンプルソースをあまり見てませんでしたが、

// テスト対象のインスタンスフィールドにあるHttpClientをモックに差し替える
mFxRateLoader.mHttpclient = mockHttpClient;


_人人人人人人人人人人人人人人人人_
> インスタンスフィールドを差し替える <
 ̄^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^^ ̄


結局、テスト対象のプロジェクトを差し替えられるようにしておかないといけないのと、Overrideで差し替えるのとそんな大きな差はないのかなあと思ったりもします。あ、でも、戻り値をちょっとずつ替えてテストしたい場合は、差し替えのたびにOverride書くよりはすっきりするのかもしれませんが。「テストしづらいものをテストする」とあったので、勝手に夢のような置き換えが行われると勘違いしてました(;^_^A

ちなみに、基本的にはpublicじゃないとこのような差し替えはできないですが、privateで宣言してても可能です。差し替えの部分はこんな風に

Class c = mFxRateLoader.getClass();
Field fld = c.getDeclaredField("mHttpclient");
fld.setAccessible(true);
fld.set(mFxRateLoader, mockHttpClient);

まあでもなんとか動いてくれてモヤモヤが晴れました....


PR:テスト駆動開発入門
PR:JUnit実践入門 ~体系的に学ぶユニットテストの技法 (WEB+DB PRESS plus)
PR:Android Hacks ―プロが教えるテクニック & ツール

0 件のコメント :

コメントを投稿