WorkManager proporciona API para probar Worker
, ListenableWorker
y las variantes de ListenableWorker
(CoroutineWorker
y RxWorker
).
Cómo probar los trabajadores
Supongamos que tenemos un elemento Worker
que se ve de la siguiente manera:
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(); } } }
Para probar este Worker
, puedes usar TestWorkerBuilder
. Este compilador ayuda a compilar instancias de Worker
que se pueden usar para probar la lógica empresarial.
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 = TestWorkerBuilderS<leepWorker(> 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
también se puede usar a fin de establecer etiquetas, como inputData
o runAttemptCount
, para que puedas verificar el estado del trabajador de forma aislada. Considera un ejemplo en el que SleepWorker
toma una duración de suspensión como datos de entrada, en lugar de que esta sea una constante definida en el trabajador:
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(); } } }
En SleepWorkerTest
, puedes proporcionar los datos de entrada a tu TestWorkerBuilder
a fin de satisfacer las necesidades de 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 = TestWorkerBuilderS<leepWorker(> 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())); } }
Para obtener más detalles sobre la API de TestWorkerBuilder
, consulta la página de referencia de TestListenableWorkerBuilder
, la superclase de TestWorkerBuilder
.
Cómo probar ListenableWorker y sus variantes
Para probar un ListenableWorker
o sus variantes (CoroutineWorker
y RxWorker
), usa TestListenableWorkerBuilder
.
La diferencia principal entre TestWorkerBuilder
y un TestListenableWorkerBuilder
es que TestWorkerBuilder
te permite especificar el Executor
que se usa en segundo plano para ejecutar el Worker
, mientras que TestListenableWorkerBuilder
se basa en la lógica de subprocesos de la implementación de ListenableWorker
.
Por ejemplo, supongamos que necesitamos probar un CoroutineWorker
que se ve de la siguiente manera:
class SleepWorker(context: Context, parameters: WorkerParameters) :
CoroutineWorker(context, parameters) {
override suspend fun doWork(): Result {
delay(1000L) // milliseconds
return Result.success()
}
}
Para probar SleepWorker
, primero creamos una instancia del trabajador mediante TestListenableWorkerBuilder
y, luego, llamamos a su función doWork
dentro de una corrutina.
@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()))
}
}
}
Tiene sentido que runBlocking
sea un compilador de corrutinas para tus pruebas, de modo que cualquier código que se ejecute de manera asíncrona lo haga en paralelo.
Probar una implementación de RxWorker
es similar a probar CoroutineWorker
, ya que TestListenableWorkerBuilder
puede controlar cualquier subclase de ListenableWorker
.
Considera una versión de SleepWorker
que usa RxJava en lugar de corrutinas.
Kotlin
class SleepWorker( context: Context, parameters: WorkerParameters ) : RxWorker(context, parameters) { override fun createWork(): SingleR<esult >{ 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 SingleR<esult >createWork() { return Single.just(Result.success()) .delay(1000L, TimeUnit.MILLISECONDS); } }
Una versión de SleepWorkerTest
que prueba un RxWorker
puede parecer similar a la versión que probó un CoroutineWorker
. Usas el mismo TestListenableWorkerBuilder
, pero ahora puedes llamar a la función createWork
de RxWorker
. createWork
muestra un Single
que puedes usar para verificar el comportamiento del trabajador. TestListenableWorkerBuilder
controla las complejidades de los subprocesos y ejecuta el código del trabajador en paralelo.
Kotlin
@RunWith(AndroidJUnit4::class) class SleepWorkerTest { private lateinit var context: Context @Before fun setUp() { context = ApplicationProvider.getApplicationContext() } @Test fun testSleepWorker() { val worker = TestListenableWorkerBuilderS<leepWorker(>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()))); } }