问题 使用JUnit和JDK测试Android代码


我正在为我的Android代码编写一些POJO测试。

我想用JDK本地运行它们(不是在模拟器上使用Dalvik) - 速度,JUnit 4,Mockito,并且能够在没有设备的情况下运行无头 - 所以我在Eclipse中有一个单独的“Java”项目。

如果我正在测试的方法恰好引用了Android SDK中的任何内容,例如: android.util.Log,测试失败 - 这是有道理的,因为 android.jar 不在类路径中。重现我有这个测试用例:

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的测试。斯科特的PowerMock建议是我需要它的下一步。

稍后编辑Robolectric


11776
2017-09-12 14:35


起源



答案:


我知道没有嘲笑android.jar。我使用Powermock来模拟一切。你可以做的一件事就是帮助你进行繁重的模拟,就是让你的扩展的android类如活动,片段,广播器等变薄,并让它们委托给pojo类。你可以做出一个基于风险的决定,不要隔离单元测试android扩展类,而是集成单元通过android测试框架或其他像Robotium测试它们。

对于Android中的真正隔离单元测试,对于我来说,对java jvm进行单元测试,所有合作类都是最好的方法。


3
2017-09-12 16:56



+1好点,我会试试PowerMock。超出任何相关链接 sites.google.com/site/androiddevtesting ? - orip
我以前没见过这个链接,但它很棒,感谢分享。当我试图找出模拟android jar类所需的各种方法时,我发现自己经常在他们的网站上引用Powermock“用法”部分: code.google.com/p/powermock。 - Scott


答案:


我知道没有嘲笑android.jar。我使用Powermock来模拟一切。你可以做的一件事就是帮助你进行繁重的模拟,就是让你的扩展的android类如活动,片段,广播器等变薄,并让它们委托给pojo类。你可以做出一个基于风险的决定,不要隔离单元测试android扩展类,而是集成单元通过android测试框架或其他像Robotium测试它们。

对于Android中的真正隔离单元测试,对于我来说,对java jvm进行单元测试,所有合作类都是最好的方法。


3
2017-09-12 16:56



+1好点,我会试试PowerMock。超出任何相关链接 sites.google.com/site/androiddevtesting ? - orip
我以前没见过这个链接,但它很棒,感谢分享。当我试图找出模拟android jar类所需的各种方法时,我发现自己经常在他们的网站上引用Powermock“用法”部分: code.google.com/p/powermock。 - Scott


我有同样的问题。我想在本地测试简单的POJO。
具体来说,我的代码想要使用android.util.Base64。
我最终做的是使用SDK安装Android 4源,并将android.util.Base64类复制到我的项目中。
令人惊讶的是,这很有效。


4
2018-06-26 07:04



是的,我最终创建了一个“Base64Encoder”类型的接口,实现它 android.util.Base64 在应用程序和与 sun.misc.BASE64Decoder 在测试中:)简单地拥有一个完整的所有库代码的JAR,并且只是绑定到运行环境的框架位是非常棒的。 - orip


我有同样的问题。我想在本地测试简单的业务逻辑。 具体来说,我的代码使用 android.util.SparseArray<E>

我尝试了3种不同的方法,可以使用junit在android之外进行测试。

  • 在我的业务逻辑中,我创建了一个接口并将其附加到 MySparseArray<E> 继承自 SparseArray<E>。在junit-test中,我重新使用了接口 HashMap<Integer, E>。这是有效的,但从长远来看,这需要做很多工作才能使业务逻辑单元可测试 android.* 是必要的。
  • 正如@Tal Weiss所建议的,我添加了所需类的android java源代码: android.util.SparseArray.java 用的 com.android.internal.util.ArrayUtils.java。这也有效,但我不想添加更多的android源代码,特别是如果有更多的依赖项
  • 我下载了一个存根二进制文件 android.jar 从旧的Android 2.2 http://grepcode.com/snapshot/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1 并将其作为lib包含在我的junit-java-project中。此jar仅包含名称空间的类 android.*com.android.*dalvik.* 和 framework.base.*。这也有效。

目前我成功避免使用 android.* 除了 SparseArray<E> 在我的业务层中,并且不依赖于Context,Activity或Service。我本来可以用的 HashMap<Integer, E> 在android-business层而不是 SparseArray<E>


2
2017-10-08 18:56



我试过了 github.com/bjoernQ/unmock-plugin 在JUnit测试中使用SparseArray并且在添加keepStartingWith“dalvik.system”之后它可以工作。在unMock部分。 - Alexey


unmock-plugin可以提供帮助 https://github.com/bjoernQ/unmock-plugin。就我而言,它适用于SparseArray。


1
2017-08-09 19:48





惯于 嵌入式android / junit测试 做你想要的?


0
2017-09-12 15:31



到目前为止,我已经使用它在模拟器或实际设备上使用InstrumentationTestRunner运行测试。当我想测试一个活动或服务时,它是合适的,但是当我只想测试一些与Android平台无关的普通旧逻辑时。我错过了什么吗? - orip
我认为第一个子弹谈论'普通的老junit'测试,为你的'普通老逻辑':) - KevinDTimm
当然,但据我所知,我要么必须在模拟器或设备上运行它们,要么得到“Stub!”与现在相同的例外:( - orip