WorkManager fournit des API pour tester un Worker
, un ListenableWorker
, et les variantes ListenableWorker
(CoroutineWorker
et RxWorker
).
Test des nœuds de calcul
Imaginons un Worker
qui se présente comme suit :
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(); } } }
Pour tester ce Worker
, vous pouvez utiliser TestWorkerBuilder
. Ce compilateur permet de créer des instances de Worker
pouvant être utilisées pour tester la logique métier.
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
peut également être utilisé pour définir des balises telles que inputData
ou runAttemptCount
afin de vérifier l'état des nœuds de calcul de manière isolée. Prenons l'exemple où SleepWorker
considère une durée de veille comme donnée d'entrée plutôt que comme constante définie dans le nœud de calcul :
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(); } } }
Dans SleepWorkerTest
, vous pouvez fournir ces données d'entrée à votre TestWorkerBuilder
pour répondre aux besoins 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())); } }
Pour en savoir plus sur l'API TestWorkerBuilder
, consultez la page de référence de TestListenableWorkerBuilder
, la super-classe de TestWorkerBuilder
.
Test de ListenableWorker et de ses variantes
Pour tester un ListenableWorker
ou ses variantes (CoroutineWorker
et RxWorker
), utilisez
TestListenableWorkerBuilder
.
La principale différence entre TestWorkerBuilder
et TestListenableWorkerBuilder
est que TestWorkerBuilder
vous permet de spécifier l'arrière-plan Executor
utilisé pour exécuter Worker
, tandis que TestListenableWorkerBuilder
repose sur la logique de threading de l'implémentation de ListenableWorker
.
Par exemple, supposons que nous devions tester CoroutineWorker
, qui se présente comme suit :
class SleepWorker(context: Context, parameters: WorkerParameters) :
CoroutineWorker(context, parameters) {
override suspend fun doWork(): Result {
delay(1000L) // milliseconds
return Result.success()
}
}
Pour tester SleepWorker
, nous commençons par créer une instance de nœud de calcul à l'aide de TestListenableWorkerBuilder
, puis nous appelons sa fonction doWork
dans une 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
est pertinent en tant qu'outil de création de coroutines pour vos tests. Ainsi, tout code pouvant s'exécuter de manière asynchrone est exécuté en parallèle.
Le test d'une implémentation de RxWorker
est semblable au test de CoroutineWorker
, car TestListenableWorkerBuilder
peut gérer n'importe quelle sous-classe de ListenableWorker
.
Prenons l'exemple d'une version de SleepWorker
qui utilise RxJava au lieu de coroutines.
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); } }
Une version de SleepWorkerTest
qui teste un RxWorker
peut ressembler à la version qui a testé un CoroutineWorker
. Vous utilisez le même TestListenableWorkerBuilder
, mais appelez maintenant la fonction createWork
de RxWorker
. createWork
renvoie un Single
que vous pouvez utiliser pour vérifier le comportement de votre nœud de calcul. TestListenableWorkerBuilder
gère toutes les complexités de thread et exécute le code de vos nœuds de calcul en parallèle.
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()))); } }