我正在为我的 Android 代码编写一些 POJO 测试。
我想使用 JDK(而不是模拟器上的 Dalvik)在本地运行它们 - 为了速度、JUnit 4、Mockito,并且能够在没有设备的情况下运行 headless - 所以我在 Eclipse 中有一个单独的“Java”项目。
如果我正在测试的方法碰巧引用了 Android SDK 中的任何内容,例如 android.util.Log
,则测试失败 - 这是有道理的,因为 android.jar
不是“ t 在类路径中。为了重现我有这个测试用例:
public class FooTests {
@Test
public void testFoo() {
android.util.Log.d("x", "y");
}
}
如果我将 android.jar
显式添加到测试项目的类路径中,我会得到异常,例如
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.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
是否有一种方法可以使代码工作而无需模拟 Android SDK 的最后一点依赖性?也许模拟的 android.jar
已经存在?
编辑:现在我最终包装了像 android.util.Log
这样的类并将它们注入到实例中,以进行经典的基于 IOC 的测试。 Scott 的 PowerMock 建议是我需要时的下一步。
稍后编辑:Robolectric!
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.internal.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!
发布评论
评论(5)
我也有同样的问题。我想在本地测试简单的 POJO。
具体来说,我的代码想要使用 android.util.Base64。
我最终做的是使用 SDK 安装 Android 4 源代码,并将 android.util.Base64 类复制到我的项目中。
令人惊讶的是,这有效。
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.
据我所知,没有模拟的 android.jar 。我使用 Powermock 来模拟一切。为了帮助处理繁重的模拟,您可以做的一件事是使您的扩展 Android 类(如 Activity、Fragment、Broadcasters 等)变薄,并让它们委托给 pojo 类。您可以做出基于风险的决定,不对 Android 扩展类进行隔离单元测试,而是通过 Android 测试框架或其他类似 Robotium 的工具对它们进行集成单元测试。
对于 Android 中真正的隔离单元测试,对我来说,在 java jvm 上进行单元测试,模拟所有协作类是最好的方法。
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.
我也有同样的问题。我想在本地测试简单的业务逻辑。
具体来说,我的代码使用
android.util.SparseArray
。我尝试了 3 种不同的方法来使其可以在 android 之外使用 junit 进行测试。
SparseArray
的MySparseArray
。在 junit-test 中,我使用HashMap
重新实现了接口。这是可行的,但从长远来看,如果需要其他android.*
,那么要使业务逻辑可进行单元测试,这需要做很多工作。com.android.internal.util.ArrayUtils.java
的android.util.SparseArray.java
>。这也有效,但我不喜欢添加更多的 android 源,特别是如果有更多的依赖项,android.*
、com.android.*
、dalvik.*
和framework.base.* 的类
。这也有效。目前,我成功地避免在业务层中使用除
SparseArray
之外的android.*
类,并且不依赖于 Context、Activity 或 Service。我可以在 android-business 层中使用HashMap
而不是SparseArray
。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.
MySparseArray<E>
that inherits fromSparseArray<E>
. In the junit-test I re-implemented the interface usingHashMap<Integer, E>
. This works but in the long run this is to much work to make business logic unit-testable if otherandroid.*
are required.android.util.SparseArray.java
that usescom.android.internal.util.ArrayUtils.java
. This works, too but I don't like to add more android sources, especially if there are much more dependenciesandroid.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 namespacesandroid.*
,com.android.*
,dalvik.*
andframework.base.*
. This works too.Currently I succeeded to avoid using
android.*
classes exceptSparseArray<E>
in my business layer and has no dependency to Context, Activity or Service. I could have usedHashMap<Integer, E>
in the android-business layer instead ofSparseArray<E>
.unmock-plugin 可以帮助 https://github.com/bjoernQ/unmock-plugin。就我而言,它适用于 SparseArray。
unmock-plugin could help https://github.com/bjoernQ/unmock-plugin. In my case it works with SparseArray.
嵌入式 android/junit 测试不会做你想要的吗?
Won't the embedded android/junit tests do what you want?