スキップしてメイン コンテンツに移動

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

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


[環境]
  • 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 ―プロが教えるテクニック & ツール

コメント

このブログの人気の投稿

Javaでprivateなfieldやmethodにアクセスする

JUnitでテストしてると、privateなフィールドにアクセスして、値を参照したりセットしたりしたくなるわけですが、よく使うのでメモしておきます。 例えば、次のような対象のクラスがあるとします。 public class ParentClass { private String hoge = "ParentClass!!"; public void dispMsg() { System.out.println("dispMsg:" + hoge); } private void privateDispMsg(String msg) { System.out.println("dispMsg:" + msg); } }

GolangでWindows GUIアプリケーション

GUIアプリ作成の前提 社内ツールとしてexeで配布 開発環境はGoLandを使う 社内ツールとしてexeを配布ということであれば、Visual StudioでC#による開発だと思います。しかしながら、Go言語を習得したいのと、GoLandの補完機能が便利で、Android Studio使っていたこともあり、とっつきやすいという点からGo縛りでGUIアプリケーションを考えたいと思います。 lxn/walk Windows application library kit for Go. Windows向けしか考えていないので、まずこのライブラリなのですが、ボタンやコンボボックスが思ったように並ばなかったり、手軽にイメージボタンを配置したりなど、簡単にレイアウトを変更できない課題に直面しました。レイアウト作成だけで時間を取られてしまいます。そう言えば、Androidアプリ開発のときは、XMLでデザイン部分を切り離してたのを思い出して、今回の調査の運びとなりました。 fyne-io/fyne Cross platform native GUIs designed for Go based on Material Design. Supports: Linux, macOS, Windows, BSD, iOS and Android. walkと比べると、クロスプラットフォームで作成できるのですが、こちらもコードの中にデザインを書いていく形でした。 therecipe/qt therecipe/qt allows you to write Qt applications entirely in Go or JavaScript. Qt Creatorなるものがあるようで、デザイン部分を切り離せる印象はあるものの、最新のPCでもビルドに時間がかかるようで、学習コストもかかるという記事を見かけて断念しました。 どうしたものかとツイートしましたら、下記のようにご助言をいただいた。 同じ課題に対し色々試した結果、PWAのフルキャッシュドに落ち着いた。中身はGo+WASMで。 https://t.co/e60whDTV16 — のぼのぼ📡 (@nobonobo) July 21, 2020 PWA 早速調べてみました。Googleが進めているプロジェクトで、ネイティブアプリのよ

Eclipseの高速化メモ

Eclipseが重いと一言に言っても、いろいろな工程での話があると思いますが、過去記事のなども含めてこの記事にピックアップしておきたいと思います。以下はWindows環境での話です。