单元测试WorkManager时定期工作未达到运行状态

时间:2019-07-18 17:31:22

标签: java android unit-testing android-testing android-workmanager

我从PeriodicWorkRequest创建了一个SyncDatabaseWorker,如下所示:

class SyncDatabaseWorker(ctx: Context, params: WorkerParameters) : RxWorker(ctx, params) {

    private val dataManager: DataManager = App.getDataManager()

    override fun createWork(): Single<Result> {
        return Single.create { emitter ->

            dataManager.loadStoresFromServer()
                    .subscribe(object : SingleObserver<List<Store>> {
                        override fun onSubscribe(d: Disposable) {
                        }

                        override fun onSuccess(storeList: List<Store>) {
                            if (!storeList.isEmpty()) {
                                emitter.onSuccess(Result.success())
                            } else {
                                emitter.onSuccess(Result.retry())
                            }
                        }

                        override fun onError(e: Throwable) {
                            emitter.onSuccess(Result.failure())
                        }
                    })
        }
    }

    companion object {
        fun prepareSyncDBWorker(): PeriodicWorkRequest {
            val constraints = Constraints.Builder()
                    .setRequiredNetworkType(NetworkType.CONNECTED)
                    .build()

            val myWorkBuilder = PeriodicWorkRequest.Builder(SyncDatabaseWorker::class.java, 7, TimeUnit.DAYS)
                    .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.DAYS) // Backoff retry after 1 day
                    .setConstraints(constraints)

            return myWorkBuilder.build()
        }
    }
}

然后我像这样在Google's guide上编写单元测试:

@RunWith(AndroidJUnit4::class)
class SyncDatabaseWorkerTest {
    private lateinit var context: Context

    @Before
    fun setup() {
        context = InstrumentationRegistry.getInstrumentation().targetContext

        val config = Configuration.Builder()
                .setMinimumLoggingLevel(Log.DEBUG)
                .setExecutor(SynchronousExecutor())
                .build()

        // Initialize WorkManager for instrumentation tests.
        WorkManagerTestInitHelper.initializeTestWorkManager(context, config)
    }

    @Test
    @Throws(Exception::class)
    fun testPeriodicWork_WithConstrains() {
        // Create request
        val request = SyncDatabaseWorker.prepareSyncDBWorker()

        val workManager = WorkManager.getInstance(context)
        val testDriver = WorkManagerTestInitHelper.getTestDriver(context)

        // Enqueue and wait for result.
        workManager.enqueue(request).result.get()

        // Check work request is enqueued
        var workInfo = workManager.getWorkInfoById(request.id).get()
        assertThat(workInfo.state, `is`(WorkInfo.State.ENQUEUED))

        // Tells the testing framework the period delay & all constrains is met
        testDriver!!.setPeriodDelayMet(request.id)
        testDriver.setAllConstraintsMet(request.id)

        // Check work request is running
        workInfo = workManager.getWorkInfoById(request.id).get()
        assertThat(workInfo.state, `is`(WorkInfo.State.RUNNING))
    }
}

即使满足期间延迟和所有约束,它始终处于ENQUEUED状态。

Expected: is <RUNNING>
but: was <ENQUEUED>

当我调试测试并发现createWork(): Single<Result>方法也被触发时,为什么状态不是RUNNING

这种方法可能是我错了,但是有关单元测试WorkManager的文档现在很少了,我不知道正确的方法。

2 个答案:

答案 0 :(得分:1)

由于您使用的是同步执行器,因此您永远不会真正看到处于RUNNING状态的工作-它应该已经执行了。我怀疑您的工作实际上已被标记为重试,因此再次进入ENQUEUED状态。您应该可以通过设置断点或查看日志来验证这一点。

答案 1 :(得分:1)

鉴于您正在使用PeriodicWorkRequest执行SynchronousExecutor,您将永远不会看到WorkRequest处于RUNNING状态。在您断言它位于RUNNING中之前,它将完成执行。

在您的Result.success()中返回Result.failure()doWork()之后,WorkRequest回到下一个期间的ENQUEUED(假设这是定期的请求)。