WorkManager offre una
work-testing artefatto che consente di testare i worker.
Configura
Per utilizzare l'artefatto work-testing, aggiungilo come androidTestImplementation
della dipendenza in build.gradle.
Alla moda
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") }
Per saperne di più sull'aggiunta di dipendenze, consulta la documentazione nel Note di rilascio di WorkManager.
Concetti
work-testing offre un'implementazione speciale di WorkManager per la modalità di test,
che viene inizializzato utilizzando
WorkManagerTestInitHelper
L'artefatto work-testing fornisce anche
SynchronousExecutor
che semplifica la scrittura dei test in modo sincrono, senza dover
gestire più thread, blocchi o fermi.
Ecco un esempio su come utilizzare tutte queste classi insieme.
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); } }
Test struttura
Ora che WorkManager è stato inizializzato in modalità di test, puoi dai lavoratori.
Supponiamo che tu abbia un EchoWorker che prevede inputData e semplicemente
copia (eco) l'input in 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); } } }
Test di base
Di seguito è riportato un test di strumentazione Android che testa EchoWorker. Il principale
è fondamentale che testare EchoWorker in modalità di test è molto simile
useresti EchoWorker in un'applicazione reale.
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)); }
Scriviamo un altro test per assicurarci che quando EchoWorker non riceva alcun input
, il valore previsto per 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)); }
Simulare vincoli, ritardi e lavoro periodico
WorkManagerTestInitHelper ti fornisce un'istanza
TestDriver che può essere utilizzato
per simulare il ritardo iniziale, le condizioni in cui i vincoli vengono soddisfatti
ListenableWorker istanze e intervalli per PeriodicWorkRequest
di Compute Engine.
Ritardi iniziali del test
I worker possono avere ritardi iniziali. Per testare EchoWorker con un initialDelay,
anziché dover attendere il initialDelay nel test, puoi usare
TestDriver per contrassegnare il ritardo iniziale della richiesta di lavoro come soddisfatto utilizzando
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)); }
Test dei vincoli
TestDriver può essere utilizzato anche per contrassegnare i vincoli come soddisfatti utilizzando
setAllConstraintsMet. Ecco un esempio su come testare un Worker
con vincoli.
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)); }
Verifica periodica
TestDriver espone anche un setPeriodDelayMet che può essere utilizzato per
indicano che un intervallo è completo. Ecco un esempio di
setPeriodDelayMet in uso.
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)); }