WorkManager 提供了一个 work-testing
工件,可以协助进行工作器测试。
设置
如需使用 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 已在测试模式中初始化,您可以测试您的工作器了。
假设您有一个 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); } } }
基本测试
以下是一个对 EchoWorker
进行测试的 Android 插桩测试。这里的要点是,在测试模式中测试 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 = OneTimeWorkRequestBuilderE<choWorker(>) .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 = OneTimeWorkRequestBuilderE<choWorker(>) .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
实例的间隔。
测试初始延迟
工作器可以具有初始延迟。如需测试具有 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 = OneTimeWorkRequestBuilderE<choWorker(>) .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 = OneTimeWorkRequestBuilderE<choWorker(>) .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 = PeriodicWorkRequestBuilderE<choWorker(>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)); }