开发者

Testing Android code with JUnit and the JDK

I'm writing some POJO tests for my Android code.

I want to run them locally with the JDK (not with Dalvik on the emulator) - for speed, JUnit 4, Mockito, and being able to run headless without a device - so I have a separate "Java" project in Eclipse.

If the method I'm testing happens to reference anything from the Android SDK, e.g. android.util.Log, the test fails - this makes sense because android.jar isn't in the classpath. To reproduce I have this test case:

public class FooTests {
  @Test
  public void testFoo() {
    android.util.Log.d("x", "y");
  }
}

If I add android.jar explicitly to the test project's classpath, I get exceptions like

java.lang.RuntimeException: Stub!
  at android.util.Log.d(Log.java:7)
  at com.example.FooTests.testFoo(FooTests.java:39)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  ...
  at org.eclipse.jdt.interna开发者_JS百科l.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Is there a way to make the code work without mocking out every last bit of Android SDK dependency? Perhaps a mocked-out android.jar already exists?

EDIT: For now I ended up wrapping classes like android.util.Log and injecting them into the instances, for classic IOC-based testing. Scott's PowerMock suggestion is my next step when I'll need it.

LATER EDIT: Robolectric!


I had the same problem. I wanted to test simple POJOs locally.
Specifically, my code wanted to use android.util.Base64.
What I ended up doing was to use the SDK to install the Android 4 sources, and copied the android.util.Base64 class to my project.
Surprisingly enough, this worked.


There's no mocked out android.jar that I know of. I use Powermock to mock everything out. One thing you can do to help with the heavy mocking is to make your extended android classes like activity, fragments, broadcasters, etc. thin and have them delegate to pojo classes. You could make a risk based decision not to isolation unit test the android extended classes, and instead integration unit test them via the android testing framework or something else like Robotium.

For true isolation unit testing in Android, for me unit testing on the java jvm mocking all out all collaborating classes is the best way to go.


I had the same problem. I wanted to test simple business logic locally. Specifically, my code uses android.util.SparseArray<E>.

I tried 3 different approaches to make it testable with junit outside android.

  • In my business logic I created an interface and attached it to MySparseArray<E> that inherits from SparseArray<E>. In the junit-test I re-implemented the interface using HashMap<Integer, E>. This works but in the long run this is to much work to make business logic unit-testable if other android.* are required.
  • As suggested by @Tal Weiss I added the android java sources of the required classes: android.util.SparseArray.java that uses com.android.internal.util.ArrayUtils.java. This works, too but I don't like to add more android sources, especially if there are much more dependencies
  • I downloaded a stub free binary android.jar for an old android 2.2 from http://grepcode.com/snapshot/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1 and included it as lib into my junit-java-project. This jar contains only classes for namespaces android.*, com.android.*, dalvik.* and framework.base.*. This works too.

Currently I succeeded to avoid using android.* classes except SparseArray<E> in my business layer and has no dependency to Context, Activity or Service. I could have used HashMap<Integer, E> in the android-business layer instead of SparseArray<E>.


unmock-plugin could help https://github.com/bjoernQ/unmock-plugin. In my case it works with SparseArray.


Won't the embedded android/junit tests do what you want?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜