WorkManager 提供一个 work-testing
工件,有助于测试您的 worker。
设置
要使用 work-testing
工件,请将其作为 androidTestImplementation
依赖项添加到 build.gradle
中。
Groovy
dependencies { def work_version = "2.5.0" ... // optional - Test helpers androidTestImplementation "androidx.work:work-testing:$work_version" }
Kotlin
dependencies { val work_version = "2.4.0" ... // optional - Test helpers androidTestImplementation("androidx.work:work-testing:$work_version") }
有关添加依赖项的更多信息,请查看 WorkManager 版本说明 中的声明依赖项部分。
概念
work-testing
为测试模式提供了一种特殊的 WorkManager 实现,该实现使用 WorkManagerTestInitHelper
初始化。
work-testing
工件还提供了一个 SynchronousExecutor
,它使以同步方式编写测试变得更容易,而无需处理多个线程、锁或闩锁。
以下是如何将所有这些类一起使用的一个示例。
Kotlin
@RunWith(AndroidJUnit4::class) class BasicInstrumentationTest { @Before fun setup() { val context = InstrumentationRegistry.getTargetContext() val config = Configuration.Builder() .setMinimumLoggingLevel(Log.DEBUG) .setExecutor(SynchronousExecutor()) .build() // Initialize WorkManager for instrumentation tests. WorkManagerTestInitHelper.initializeTestWorkManager(context, config) } }
Java
@RunWith(AndroidJUnit4.class) public class BasicInstrumentationTest { @Before public void setup() { Context context = InstrumentationRegistry.getTargetContext(); Configuration config = new Configuration.Builder() .setMinimumLoggingLevel(Log.DEBUG) .setExecutor(new SynchronousExecutor()) .build(); // Initialize WorkManager for instrumentation tests. WorkManagerTestInitHelper.initializeTestWorkManager( context, config); } }
结构化测试
现在 WorkManager 已在测试模式下初始化,您已准备好测试您的 worker。
假设您有一个 EchoWorker
,它需要一些 inputData
,并且只是将输入复制(回显)到 outputData
中。
Kotlin
class EchoWorker(context: Context, parameters: WorkerParameters) : Worker(context, parameters) { override fun doWork(): Result { return when(inputData.size()) { 0 -> Result.failure() else -> Result.success(inputData) } } }
Java
public class EchoWorker extends Worker { public EchoWorker(Context context, WorkerParameters parameters) { super(context, parameters); } @NonNull @Override public Result doWork() { Data input = getInputData(); if (input.size() == 0) { return Result.failure(); } else { return Result.success(input); } } }
基本测试
下面是一个 Android Instrumentation 测试,它测试 EchoWorker
。这里的主要要点是,在测试模式下测试 EchoWorker
与在实际应用程序中使用 EchoWorker
非常相似。
Kotlin
@Test @Throws(Exception::class) fun testSimpleEchoWorker() { // Define input data val input = workDataOf(KEY_1 to 1, KEY_2 to 2) // Create request val request = OneTimeWorkRequestBuilder<EchoWorker>() .setInputData(input) .build() val workManager = WorkManager.getInstance(applicationContext) // Enqueue and wait for result. This also runs the Worker synchronously // because we are using a SynchronousExecutor. workManager.enqueue(request).result.get() // Get WorkInfo and outputData val workInfo = workManager.getWorkInfoById(request.id).get() val outputData = workInfo.outputData // Assert assertThat(workInfo.state, `is`(WorkInfo.State.SUCCEEDED)) assertThat(outputData, `is`(input)) }
Java
@Test public void testSimpleEchoWorker() throws Exception { // Define input data Data input = new Data.Builder() .put(KEY_1, 1) .put(KEY_2, 2) .build(); // Create request OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(EchoWorker.class) .setInputData(input) .build(); WorkManager workManager = WorkManager.getInstance(getApplicationContext()); // Enqueue and wait for result. This also runs the Worker synchronously // because we are using a SynchronousExecutor. workManager.enqueue(request).getResult().get(); // Get WorkInfo and outputData WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); Data outputData = workInfo.getOutputData(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.SUCCEEDED)); assertThat(outputData, is(input)); }
让我们再编写一个测试,确保当 EchoWorker
没有收到任何输入数据时,预期的 Result
是 Result.failure()
。
Kotlin
@Test @Throws(Exception::class) fun testEchoWorkerNoInput() { // Create request val request = OneTimeWorkRequestBuilder<EchoWorker>() .build() val workManager = WorkManager.getInstance(applicationContext) // Enqueue and wait for result. This also runs the Worker synchronously // because we are using a SynchronousExecutor. workManager.enqueue(request).result.get() // Get WorkInfo val workInfo = workManager.getWorkInfoById(request.id).get() // Assert assertThat(workInfo.state, `is`(WorkInfo.State.FAILED)) }
Java
@Test public void testEchoWorkerNoInput() throws Exception { // Create request OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(EchoWorker.class) .build(); WorkManager workManager = WorkManager.getInstance(getApplicationContext()); // Enqueue and wait for result. This also runs the Worker synchronously // because we are using a SynchronousExecutor. workManager.enqueue(request).getResult().get(); // Get WorkInfo WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.FAILED)); }
模拟约束、延迟和周期性工作
WorkManagerTestInitHelper
为您提供了一个 TestDriver
实例,该实例可用于模拟初始延迟、约束满足的条件 ListenableWorker
实例,以及 PeriodicWorkRequest
实例的时间间隔。
测试初始延迟
Worker 可以具有初始延迟。要测试具有 initialDelay
的 EchoWorker
,您无需在测试中等待 initialDelay
,而是可以使用 TestDriver
将工作请求的初始延迟标记为已满足,方法是使用 setInitialDelayMet
。
Kotlin
@Test @Throws(Exception::class) fun testWithInitialDelay() { // Define input data val input = workDataOf(KEY_1 to 1, KEY_2 to 2) // Create request val request = OneTimeWorkRequestBuilder<EchoWorker>() .setInputData(input) .setInitialDelay(10, TimeUnit.SECONDS) .build() val workManager = WorkManager.getInstance(getApplicationContext()) // Get the TestDriver val testDriver = WorkManagerTestInitHelper.getTestDriver() // Enqueue workManager.enqueue(request).result.get() // Tells the WorkManager test framework that initial delays are now met. testDriver.setInitialDelayMet(request.id) // Get WorkInfo and outputData val workInfo = workManager.getWorkInfoById(request.id).get() val outputData = workInfo.outputData // Assert assertThat(workInfo.state, `is`(WorkInfo.State.SUCCEEDED)) assertThat(outputData, `is`(input)) }
Java
@Test public void testWithInitialDelay() throws Exception { // Define input data Data input = new Data.Builder() .put(KEY_1, 1) .put(KEY_2, 2) .build(); // Create request OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(EchoWorker.class) .setInputData(input) .setInitialDelay(10, TimeUnit.SECONDS) .build(); WorkManager workManager = WorkManager.getInstance(myContext); // Get the TestDriver TestDriver testDriver = WorkManagerTestInitHelper.getTestDriver(); // Enqueue workManager.enqueue(request).getResult().get(); // Tells the WorkManager test framework that initial delays are now met. testDriver.setInitialDelayMet(request.getId()); // Get WorkInfo and outputData WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); Data outputData = workInfo.getOutputData(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.SUCCEEDED)); assertThat(outputData, is(input)); }
测试约束
TestDriver
还可以用于使用 setAllConstraintsMet
将约束标记为已满足。以下是如何测试具有约束的 Worker
的一个示例。
Kotlin
@Test @Throws(Exception::class) fun testWithConstraints() { // Define input data val input = workDataOf(KEY_1 to 1, KEY_2 to 2) val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build() // Create request val request = OneTimeWorkRequestBuilder<EchoWorker>() .setInputData(input) .setConstraints(constraints) .build() val workManager = WorkManager.getInstance(myContext) val testDriver = WorkManagerTestInitHelper.getTestDriver() // Enqueue workManager.enqueue(request).result.get() // Tells the testing framework that all constraints are met. testDriver.setAllConstraintsMet(request.id) // Get WorkInfo and outputData val workInfo = workManager.getWorkInfoById(request.id).get() val outputData = workInfo.outputData // Assert assertThat(workInfo.state, `is`(WorkInfo.State.SUCCEEDED)) assertThat(outputData, `is`(input)) }
Java
@Test public void testWithConstraints() throws Exception { // Define input data Data input = new Data.Builder() .put(KEY_1, 1) .put(KEY_2, 2) .build(); // Define constraints Constraints constraints = new Constraints.Builder() .setRequiresDeviceIdle(true) .build(); // Create request OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(EchoWorker.class) .setInputData(input) .setConstraints(constraints) .build(); WorkManager workManager = WorkManager.getInstance(myContext); TestDriver testDriver = WorkManagerTestInitHelper.getTestDriver(); // Enqueue workManager.enqueue(request).getResult().get(); // Tells the testing framework that all constraints are met. testDriver.setAllConstraintsMet(request.getId()); // Get WorkInfo and outputData WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); Data outputData = workInfo.getOutputData(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.SUCCEEDED)); assertThat(outputData, is(input)); }
测试周期性工作
TestDriver
还公开了 setPeriodDelayMet
,它可以用于指示时间间隔已完成。以下是如何使用 setPeriodDelayMet
的一个示例。
Kotlin
@Test @Throws(Exception::class) fun testPeriodicWork() { // Define input data val input = workDataOf(KEY_1 to 1, KEY_2 to 2) // Create request val request = PeriodicWorkRequestBuilder<EchoWorker>(15, MINUTES) .setInputData(input) .build() val workManager = WorkManager.getInstance(myContext) val testDriver = WorkManagerTestInitHelper.getTestDriver() // Enqueue and wait for result. workManager.enqueue(request).result.get() // Tells the testing framework the period delay is met testDriver.setPeriodDelayMet(request.id) // Get WorkInfo and outputData val workInfo = workManager.getWorkInfoById(request.id).get() // Assert assertThat(workInfo.state, `is`(WorkInfo.State.ENQUEUED)) }
Java
@Test public void testPeriodicWork() throws Exception { // Define input data Data input = new Data.Builder() .put(KEY_1, 1) .put(KEY_2, 2) .build(); // Create request PeriodicWorkRequest request = new PeriodicWorkRequest.Builder(EchoWorker.class, 15, MINUTES) .setInputData(input) .build(); WorkManager workManager = WorkManager.getInstance(myContext); TestDriver testDriver = WorkManagerTestInitHelper.getTestDriver(); // Enqueue and wait for result. workManager.enqueue(request).getResult().get(); // Tells the testing framework the period delay is met testDriver.setPeriodDelayMet(request.getId()); // Get WorkInfo and outputData WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.ENQUEUED)); }