Testing Worker implementation
Stay organized with collections
Save and categorize content based on your preferences.
WorkManager provides APIs for testing Worker,
ListenableWorker, and the
ListenableWorker variants
(CoroutineWorker
and RxWorker).
Testing Workers
Let’s say we have a Worker which looks like this:
Kotlin
classSleepWorker(context:Context,parameters:WorkerParameters): Worker(context,parameters){ overridefundoWork():Result{ // Sleep on a background thread. Thread.sleep(1000) returnResult.success() } }
Java
publicclass SleepWorkerextendsWorker{ publicSleepWorker( @NonNullContextcontext, @NonNullWorkerParametersworkerParameters){ super(context,workerParameters); } @NonNull @Override publicResultdoWork(){ try{ Thread.sleep(1000); }catch(InterruptedExceptionignore){ returnResult.success(); } } }
To test this Worker, you can use
TestWorkerBuilder. This
builder helps build instances of Worker that can be used for the purpose of
testing business logic.
Kotlin
// Kotlin code uses the TestWorkerBuilder extension to build // the Worker @RunWith(AndroidJUnit4::class) classSleepWorkerTest{ privatelateinitvarcontext:Context privatelateinitvarexecutor:Executor @Before funsetUp(){ context=ApplicationProvider.getApplicationContext() executor=Executors.newSingleThreadExecutor() } @Test funtestSleepWorker(){ valworker=TestWorkerBuilder<SleepWorker>( context=context, executor=executor ).build() valresult=worker.doWork() assertThat(result,`is`(Result.success())) } }
Java
@RunWith(AndroidJUnit4.class) publicclass SleepWorkerJavaTest{ privateContextcontext; privateExecutorexecutor; @Before publicvoidsetUp(){ context=ApplicationProvider.getApplicationContext(); executor=Executors.newSingleThreadExecutor(); } @Test publicvoidtestSleepWorker(){ SleepWorkerworker= (SleepWorker)TestWorkerBuilder.from(context, SleepWorker.class, executor) .build(); Resultresult=worker.doWork(); assertThat(result,is(Result.success())); } }
TestWorkerBuilder can also be used to set tags, such as inputData or
runAttemptCount, so that you can verify worker state in isolation. Consider
an example in which SleepWorker takes in a sleep duration as input data
rather than it being a constant defined in the worker:
Kotlin
classSleepWorker(context:Context,parameters:WorkerParameters): Worker(context,parameters){ overridefundoWork():Result{ // Sleep on a background thread. valsleepDuration=inputData.getLong(SLEEP_DURATION,1000) Thread.sleep(sleepDuration) returnResult.success() } companionobject{ constvalSLEEP_DURATION="SLEEP_DURATION" } }
Java
publicclass SleepWorkerextendsWorker{ publicstaticfinalStringSLEEP_DURATION="SLEEP_DURATION"; publicSleepWorker( @NonNullContextcontext, @NonNullWorkerParametersworkerParameters){ super(context,workerParameters); } @NonNull @Override publicResultdoWork(){ try{ longduration=getInputData().getLong(SLEEP_DURATION,1000); Thread.sleep(duration); }catch(InterruptedExceptionignore){ returnResult.success(); } } }
In SleepWorkerTest, you can provide that input data to your
TestWorkerBuilder to satisfy the needs of SleepWorker.
Kotlin
// Kotlin code uses the TestWorkerBuilder extension to build // the Worker @RunWith(AndroidJUnit4::class) classSleepWorkerTest{ privatelateinitvarcontext:Context privatelateinitvarexecutor:Executor @Before funsetUp(){ context=ApplicationProvider.getApplicationContext() executor=Executors.newSingleThreadExecutor() } @Test funtestSleepWorker(){ valworker=TestWorkerBuilder<SleepWorker>( context=context, executor=executor, inputData=workDataOf("SLEEP_DURATION"to1000L) ).build() valresult=worker.doWork() assertThat(result,`is`(Result.success())) } }
Java
@RunWith(AndroidJUnit4.class) publicclass SleepWorkerJavaTest{ privateContextcontext; privateExecutorexecutor; @Before publicvoidsetUp(){ context=ApplicationProvider.getApplicationContext(); executor=Executors.newSingleThreadExecutor(); } @Test publicvoidtestSleepWorker(){ DatainputData=newData.Builder() .putLong("SLEEP_DURATION",1000L) .build(); SleepWorkerworker= (SleepWorker)TestWorkerBuilder.from(context, SleepWorker.class,executor) .setInputData(inputData) .build(); Resultresult=worker.doWork(); assertThat(result,is(Result.success())); } }
For more details on the TestWorkerBuilder API, see the reference page for
TestListenableWorkerBuilder,
the superclass of TestWorkerBuilder.
Testing ListenableWorker and its variants
To test a ListenableWorker or its
variants (CoroutineWorker
and RxWorker), use
TestListenableWorkerBuilder.
The main difference between TestWorkerBuilder and a
TestListenableWorkerBuilder
is that TestWorkerBuilder lets you specify the background Executor used to
run the Worker, whereas TestListenableWorkerBuilder relies on the
threading logic of the ListenableWorker implementation.
For example, suppose we need to test a CoroutineWorker which looks like this:
classSleepWorker(context:Context,parameters:WorkerParameters):
CoroutineWorker(context,parameters){
overridesuspendfundoWork():Result{
delay(1000L)// milliseconds
returnResult.success()
}
}
To test SleepWorker, we first create an instance of the Worker using
TestListenableWorkerBuilder and then call its doWork function within a
coroutine.
@RunWith(AndroidJUnit4::class)
classSleepWorkerTest{
privatelateinitvarcontext:Context
@Before
funsetUp(){
context=ApplicationProvider.getApplicationContext()
}
@Test
funtestSleepWorker(){
valworker=TestListenableWorkerBuilder<SleepWorker>(context).build()
runBlocking{
valresult=worker.doWork()
assertThat(result,`is`(Result.success()))
}
}
}
runBlocking makes sense as a coroutine builder for your tests so that any code
that would execute asynchronously is instead run in parallel.
Testing an RxWorker implementation is similar to testing CoroutineWorker, as
TestListenableWorkerBuilder can handle any subclass of ListenableWorker.
Consider a version of SleepWorker that uses RxJava instead of coroutines.
Kotlin
classSleepWorker( context:Context, parameters:WorkerParameters ):RxWorker(context,parameters){ overridefuncreateWork():Single<Result>{ returnSingle.just(Result.success()) .delay(1000L,TimeUnit.MILLISECONDS) } }
Java
publicclass SleepWorkerextendsRxWorker{ publicSleepWorker(@NonNullContextappContext, @NonNullWorkerParametersworkerParams){ super(appContext,workerParams); } @NonNull @Override publicSingle<Result>createWork(){ returnSingle.just(Result.success()) .delay(1000L,TimeUnit.MILLISECONDS); } }
A version of SleepWorkerTest that tests an RxWorker may look similar to the
version that tested a CoroutineWorker. You use the same
TestListenableWorkerBuilder but now call into RxWorker’s createWork
function. createWork returns a Single that you can use to verify the
behavior of your worker. TestListenableWorkerBuilder handles any threading
complexities and executes your worker code in parallel.
Kotlin
@RunWith(AndroidJUnit4::class) classSleepWorkerTest{ privatelateinitvarcontext:Context @Before funsetUp(){ context=ApplicationProvider.getApplicationContext() } @Test funtestSleepWorker(){ valworker=TestListenableWorkerBuilder<SleepWorker>(context).build() worker.createWork().subscribe{result-> assertThat(result,`is`(Result.success())) } } }
Java
@RunWith(AndroidJUnit4.class) publicclass SleepWorkerTest{ privateContextcontext; @Before publicvoidsetUp(){ context=ApplicationProvider.getApplicationContext(); } @Test publicvoidtestSleepWorker(){ SleepWorkerworker=TestListenableWorkerBuilder.from(context,SleepWorker.class) .build(); worker.createWork().subscribe(result-> assertThat(result,is(Result.success()))); } }