如何在单元测试中初始化 ThreeTen Android 向后移植

How to initialize ThreeTen Android backport in a Unit test

提问人:Fawwaz Yusran 提问时间:2/5/2019 更新时间:11/15/2023 访问量:1660

问:

我使用这个库在我的应用程序中存储日期和时间相关数据。当应用程序启动时,首先初始化以正常运行。所以我想问一下,在单元测试的时候如何初始化呢?例如,我想使用 、 等进行测试。AndroidThreeTenLocalDateLocalDateTime

我现在的方式是这样的:

class OverviewViewModelTest {

    @Rule
    @JvmField
    val rule = InstantTaskExecutorRule()

    @Before
    fun setup() {
        AndroidThreeTen.init(Application())
    }

    //...
}

但它抛出了这个错误:

java.lang.ExceptionInInitializerError
    at org.threeten.bp.ZoneRegion.ofId(ZoneRegion.java:143)
    at org.threeten.bp.ZoneId.of(ZoneId.java:358)
    at org.threeten.bp.ZoneId.of(ZoneId.java:286)
    at org.threeten.bp.ZoneId.systemDefault(ZoneId.java:245)
    at org.threeten.bp.Clock.systemDefaultZone(Clock.java:137)
    at org.threeten.bp.LocalDate.now(LocalDate.java:165)
Caused by: java.lang.RuntimeException: Method getAssets in android.content.ContextWrapper not mocked. See http://g.co/androidstudio/not-mocked for details.
    at android.content.ContextWrapper.getAssets(ContextWrapper.java)
    at com.jakewharton.threetenabp.AssetsZoneRulesInitializer.initializeProviders(AssetsZoneRulesInitializer.java:22)
    at org.threeten.bp.zone.ZoneRulesInitializer.initialize(ZoneRulesInitializer.java:89)
    at org.threeten.bp.zone.ZoneRulesProvider.<clinit>(ZoneRulesProvider.java:82)
    ... 32 more

那么我怎样才能让这个库在单元测试中工作呢?

Android 单元测试 threetenbp

评论

1赞 Morrison Chang 2/5/2019
相关新闻: github.com/JakeWharton/ThreeTenABP/issues/14
0赞 Anonymous 2/7/2019
您是否尝试过错误消息中的链接?“方法......没有被嘲笑。
0赞 Fawwaz Yusran 2/15/2019
我确实有。我会在下面发布一个答案。

答:

3赞 Fawwaz Yusran 2/15/2019 #1

使用 GitHub 问题的最新评论,我能够使用 Robolectric 库运行 Three Ten Android 向后移植。对于 Kotlin 用户,请勿使用最终类。相反,请使用开放类。

在应用的 中,添加:build.gradle

dependencies {
    // ...
    testImplementation('org.threeten:threetenbp:1.3.8') {
        exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
    }
}

并使用此模板使用 ThreeTenABP 编写测试:

@RunWith(RobolectricTestRunner::class)
open class DateUtilTest {

    @Test
    fun testName {
        // Write as normal
    }
}
0赞 true-mt 11/15/2023 #2

你总是可以包装你的 Android 依赖项,比如

object TimeManager {
 fun init(context: Context) {AndroidThreeTen.init(context)}
 fun now() {...}
}

在测试中,你会嘲笑 TimeManager 类 取决于你使用的模拟框架,但你会做这样的事情

every {TimeManger.now()} returns System.currentTimeMillis()

当然,您也可以使用 DI 方法

Interface TimeManager {
 fun init(context: Context)
 fun now()
}

class TimeManagerImpl : TimeManager {
     fun init(context: Context) {AndroidThreeTen.init(context)}
     fun now() {...}
}

class MockTimeManager: TimeManager {
     fun init(context: Context) {// no op}
     fun now() = System.currentTimeMillis()
}