android - Robolectric 3.0 : Mocking System. currentTimeMillis()

标签 android unit-testing robolectric

我正在尝试修改 System.currentTimeMillis() 返回的值,以便我可以执行以下操作:向数据库写入内容,模拟等待 5 分钟,对数据库进行查询(查询取决于写入值)。

[this SO thread] 中建议的代码:

ShadowSystemClock shadowClock = Robolectric.shadowOf(SystemClock.class);
shadowClock.setCurrentTimeMillis(1424369871446);

不编译,因为 shadowOf 方法被移除。尝试替代方案,例如:

ShadowSystemClock shadowClock = new ShadowSystemClock();
shadowClock.setCurrentTimeMillis(1424369871446);

似乎有 issues with overriding currentTimeMillis()但这些问题应该从 3.0 版开始修复。

我可以添加 PowerMock到我的项目并将其用于我认为的这种情况,但如果 R​​obolectric 可以做到这一点,我更愿意这样做。

更新:越来越近了,但可能遗漏了一些东西。这段代码:

ShadowSystemClock shadowClock = new ShadowSystemClock();

Log("system = " + System.currentTimeMillis() + "; shadow = " + shadowClock.currentTimeMillis() + "; time from code = " + Code.getSystemTime());

shadowClock.setCurrentTimeMillis(50000000L);

Log("system = " + System.currentTimeMillis() + "; shadow = " + shadowClock.currentTimeMillis() + "; time from code = " + Code.getSystemTime());

输出这个:

system = 1438212006879; shadow = 0; time from code = 1438212006894
system = 1438212006898; shadow = 50000000; time from code = 1438212006898

Code.getSystemTime() 正在调用正在测试的代码库。该方法仅返回 System.currentTimeMillis()。

如果 ShadowSystemClock 拦截了对 currentTimeMillis() 的调用,似乎一切都可以正常工作。有办法吗?

最佳答案

首先,因为 SystemClock 是一个完全由静态方法组成的单例类,所以不需要使用 shadowOf()shadowOf() 仅在查找对象实例 的阴影时需要。要访问 SystemClock 的影子静态方法,您只需直接调用 ShadowSystemClock 的静态方法,您永远不必通过调用实例化 ShadowSystemClock 。在您的测试代码中,您应该能够免除对 new 的调用并将 shadowClock.currentTimeMillis() 替换为 ShadowSystemClock.currentTimeMillis() .

其次,更直接地与您关于 System.currentTimeMillis() 被拦截的问题相关 - 在 Robolectric 下,这将发生,但仅适用于已被检测的代码 -也就是说,在由 Robolectric 的特殊类加载器加载时进行修改。在检测代码中,所有对 System.currentTimeMillis() 的调用都替换为调用 ShadowSystemClock.currentTimeMillis(),这就是您想要的。

因此,为了让您的测试按您希望的方式工作,您需要确保您正在测试的代码已被检测。默认情况下,Robolectric 不会对所有类执行此操作 - 仅适用于 Android 类。不幸的是,我目前无法亲自测试,但我相信您可以通过在 @Config 注释中指定包来告诉 Robolectric 检测您自己的应用程序类 - 例如,如果您将@Config(instrumentedPackages={ "my.application"}) 在您的测试类或方法上,然后告诉 Robolectric 检测“my.application”包中的所有类。这将反过来导致他们的 System.currentTimeMillis() 调用重定向到 ShadowSystemClock.currentTimeMillis(),这应该是您想要的。

这样做不同的原因是因为使用 Robolectric 的类加载器方法,无法修改 java.lang.* 包中的类,因为它们在您安装检测类加载器之前已经加载.有一个更长期的想法,即使用类似于 JMockit 所做的方法在 Robolectric 中尝试以不同方式执行此操作,这可以解决此问题。这意味着您不必显式检测所有客户端类。然而,目前这是天上掉馅饼,我不会屏住呼吸等待它 - 希望以上内容能解决您眼前的问题。

希望这对您有所帮助。

关于android - Robolectric 3.0 : Mocking System. currentTimeMillis(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31659771/

相关文章:

android - 使用 Robolectric 和 Mockito 模拟 PackageManager

java - 无法解析 "com.google.android.gms.gcm.GcmReceiver"?

java - Android - 试图实例化一个不是 fragment 的类

android - 什么是计算 android 当前速度的好方法?

iphone - 单元测试核心数据 - 异常退出,代码为 134

silverlight - 将 NUnit/ReSharper 测试移至 Silverlight

android - 让 robolectric 与 android 兼容包一起工作

java - 在 Java (Android) 中重新启用 SSL 验证

c# - 创建或获取特定的 SPTimeZone 实例

android-studio - 在 Android Studio 2.3 中运行覆盖率测试