WorkManager fornisce le API per i test di Worker
, ListenableWorker
e delle varianti ListenableWorker
(CoroutineWorker
e RxWorker
).
Operatori di test
Supponiamo di avere un Worker
simile al seguente:
Kotlin
class SleepWorker(context: Context, parameters: WorkerParameters) : Worker(context, parameters) { override fun doWork(): Result { // Sleep on a background thread. Thread.sleep(1000) return Result.success() } }
Java
public class SleepWorker extends Worker { public SleepWorker( @NonNull Context context, @NonNull WorkerParameters workerParameters) { super(context, workerParameters); } @NonNull @Override public Result doWork() { try { Thread.sleep(1000); } catch (InterruptedException ignore) { return Result.success(); } } }
Per testare questo Worker
, puoi utilizzare
TestWorkerBuilder
. Questo strumento consente di creare istanze di Worker
che possono essere utilizzate per testare la logica di business.
Kotlin
// Kotlin code uses the TestWorkerBuilder extension to build // the Worker @RunWith(AndroidJUnit4::class) class SleepWorkerTest { private lateinit var context: Context private lateinit var executor: Executor @Before fun setUp() { context = ApplicationProvider.getApplicationContext() executor = Executors.newSingleThreadExecutor() } @Test fun testSleepWorker() { val worker = TestWorkerBuilder<SleepWorker>( context = context, executor = executor ).build() val result = worker.doWork() assertThat(result, `is`(Result.success())) } }
Java
@RunWith(AndroidJUnit4.class) public class SleepWorkerJavaTest { private Context context; private Executor executor; @Before public void setUp() { context = ApplicationProvider.getApplicationContext(); executor = Executors.newSingleThreadExecutor(); } @Test public void testSleepWorker() { SleepWorker worker = (SleepWorker) TestWorkerBuilder.from(context, SleepWorker.class, executor) .build(); Result result = worker.doWork(); assertThat(result, is(Result.success())); } }
TestWorkerBuilder
può essere utilizzato anche per impostare tag, ad esempio inputData
o runAttemptCount
, in modo da poter verificare lo stato dei worker in modo isolato. Considera un esempio in cui SleepWorker
prende una durata del sonno come dati di input anziché come costante definita nel worker:
Kotlin
class SleepWorker(context: Context, parameters: WorkerParameters) : Worker(context, parameters) { override fun doWork(): Result { // Sleep on a background thread. val sleepDuration = inputData.getLong(SLEEP_DURATION, 1000) Thread.sleep(sleepDuration) return Result.success() } companion object { const val SLEEP_DURATION = "SLEEP_DURATION" } }
Java
public class SleepWorker extends Worker { public static final String SLEEP_DURATION = "SLEEP_DURATION"; public SleepWorker( @NonNull Context context, @NonNull WorkerParameters workerParameters) { super(context, workerParameters); } @NonNull @Override public Result doWork() { try { long duration = getInputData().getLong(SLEEP_DURATION, 1000); Thread.sleep(duration); } catch (InterruptedException ignore) { return Result.success(); } } }
In SleepWorkerTest
, puoi fornire questi dati di input a TestWorkerBuilder
per soddisfare le esigenze di SleepWorker
.
Kotlin
// Kotlin code uses the TestWorkerBuilder extension to build // the Worker @RunWith(AndroidJUnit4::class) class SleepWorkerTest { private lateinit var context: Context private lateinit var executor: Executor @Before fun setUp() { context = ApplicationProvider.getApplicationContext() executor = Executors.newSingleThreadExecutor() } @Test fun testSleepWorker() { val worker = TestWorkerBuilder<SleepWorker>( context = context, executor = executor, inputData = workDataOf("SLEEP_DURATION" to 1000L) ).build() val result = worker.doWork() assertThat(result, `is`(Result.success())) } }
Java
@RunWith(AndroidJUnit4.class) public class SleepWorkerJavaTest { private Context context; private Executor executor; @Before public void setUp() { context = ApplicationProvider.getApplicationContext(); executor = Executors.newSingleThreadExecutor(); } @Test public void testSleepWorker() { Data inputData = new Data.Builder() .putLong("SLEEP_DURATION", 1000L) .build(); SleepWorker worker = (SleepWorker) TestWorkerBuilder.from(context, SleepWorker.class, executor) .setInputData(inputData) .build(); Result result = worker.doWork(); assertThat(result, is(Result.success())); } }
Per maggiori dettagli sull'API TestWorkerBuilder
, consulta la pagina di riferimento per
TestListenableWorkerBuilder
,
la superclasse di TestWorkerBuilder
.
Test di FollowableWorker e delle sue varianti
Per testare una ListenableWorker
o le sue
varianti (CoroutineWorker
e RxWorker
), utilizza
TestListenableWorkerBuilder
.
La differenza principale tra TestWorkerBuilder
e
TestListenableWorkerBuilder
è che TestWorkerBuilder
consente di specificare lo sfondo Executor
utilizzato per
eseguire Worker
, mentre TestListenableWorkerBuilder
si basa sulla
logica di thread dell'implementazione di ListenableWorker
.
Ad esempio, supponiamo di dover testare un CoroutineWorker
simile al seguente:
class SleepWorker(context: Context, parameters: WorkerParameters) :
CoroutineWorker(context, parameters) {
override suspend fun doWork(): Result {
delay(1000L) // milliseconds
return Result.success()
}
}
Per testare SleepWorker
, prima creiamo un'istanza del worker utilizzando
TestListenableWorkerBuilder
, quindi chiamiamo la relativa funzione doWork
all'interno di una
coroutine.
@RunWith(AndroidJUnit4::class)
class SleepWorkerTest {
private lateinit var context: Context
@Before
fun setUp() {
context = ApplicationProvider.getApplicationContext()
}
@Test
fun testSleepWorker() {
val worker = TestListenableWorkerBuilder<SleepWorker>(context).build()
runBlocking {
val result = worker.doWork()
assertThat(result, `is`(Result.success()))
}
}
}
runBlocking
ha senso come generatore di coroutine per i tuoi test, in modo che qualsiasi codice eseguito in modo asincrono venga eseguito in parallelo.
Il test di un'implementazione RxWorker
è simile a quello di CoroutineWorker
, poiché TestListenableWorkerBuilder
può gestire qualsiasi sottoclasse di ListenableWorker
.
Considera una versione di SleepWorker
che utilizza RxJava anziché le coroutine.
Kotlin
class SleepWorker( context: Context, parameters: WorkerParameters ) : RxWorker(context, parameters) { override fun createWork(): Single<Result> { return Single.just(Result.success()) .delay(1000L, TimeUnit.MILLISECONDS) } }
Java
public class SleepWorker extends RxWorker { public SleepWorker(@NonNull Context appContext, @NonNull WorkerParameters workerParams) { super(appContext, workerParams); } @NonNull @Override public Single<Result> createWork() { return Single.just(Result.success()) .delay(1000L, TimeUnit.MILLISECONDS); } }
Una versione di SleepWorkerTest
che testa un RxWorker
potrebbe essere simile alla
versione che ha testato un CoroutineWorker
. Utilizzi lo stesso
TestListenableWorkerBuilder
, ma ora chiami la funzione createWork
di RxWorker
. createWork
restituisce un Single
che puoi utilizzare per verificare il
comportamento del worker. TestListenableWorkerBuilder
gestisce qualsiasi complessità di threading ed esegue il codice worker in parallelo.
Kotlin
@RunWith(AndroidJUnit4::class) class SleepWorkerTest { private lateinit var context: Context @Before fun setUp() { context = ApplicationProvider.getApplicationContext() } @Test fun testSleepWorker() { val worker = TestListenableWorkerBuilder<SleepWorker>(context).build() worker.createWork().subscribe { result -> assertThat(result, `is`(Result.success())) } } }
Java
@RunWith(AndroidJUnit4.class) public class SleepWorkerTest { private Context context; @Before public void setUp() { context = ApplicationProvider.getApplicationContext(); } @Test public void testSleepWorker() { SleepWorker worker = TestListenableWorkerBuilder.from(context, SleepWorker.class) .build(); worker.createWork().subscribe(result -> assertThat(result, is(Result.success()))); } }