WorkManager предоставляет API для тестирования Worker, ListenableWorker и вариантов ListenableWorker (CoroutineWorker и RxWorker).
Тестирование рабочих ВМ
Допустим, у нас есть Worker, который выглядит следующим образом:
class SleepWorker(context: Context, parameters: WorkerParameters) : Worker(context, parameters) { override fun doWork(): Result { // Sleep on a background thread. Thread.sleep(1000) return Result.success() } }
Чтобы протестировать Worker, можно использовать TestWorkerBuilder. Этот конструктор помогает создавать экземпляры Worker, которые можно использовать для тестирования бизнес-логики.
// 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())) } }
TestWorkerBuilder также можно использовать для установки тегов, таких как inputData или runAttemptCount, чтобы вы могли проверять состояние исполнителя изолированно. Рассмотрим пример, в котором SleepWorker принимает продолжительность сна в качестве входных данных, а не константы, определенной в исполнителе:
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" } }
В SleepWorkerTest вы можете предоставить эти входные данные в TestWorkerBuilder, чтобы удовлетворить потребности SleepWorker.
// 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())) } }
Дополнительную информацию об API TestWorkerBuilder можно найти на справочной странице TestListenableWorkerBuilder – надкласса TestWorkerBuilder.
Тестирование ListenableWorker и его вариантов
Чтобы протестировать ListenableWorker или его варианты (CoroutineWorker и RxWorker), используйте TestListenableWorkerBuilder.
Основное различие между TestWorkerBuilder и TestListenableWorkerBuilder заключается в том, что TestWorkerBuilder позволяет указать фоновый Executor, используемый для запуска Worker, а TestListenableWorkerBuilder полагается на логику потоков реализации ListenableWorker.
Например, нам нужно протестировать CoroutineWorker, которая выглядит следующим образом:
class SleepWorker(context: Context, parameters: WorkerParameters) : CoroutineWorker(context, parameters) { override suspend fun doWork(): Result { delay(1000L) // milliseconds return Result.success() } }
Чтобы протестировать SleepWorker, мы сначала создаем экземпляр Worker с помощью TestListenableWorkerBuilder, а затем вызываем его функцию doWork в сопрограмме.
@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 подходит для тестов в качестве построителя сопрограмм, так как любой асинхронный код будет выполняться параллельно.
Тестирование реализации RxWorker похоже на тестирование CoroutineWorker, поскольку TestListenableWorkerBuilder может обрабатывать любой подкласс ListenableWorker.
Рассмотрите версию SleepWorker, в которой вместо сопрограмм используется RxJava.
class SleepWorker( context: Context, parameters: WorkerParameters ) : RxWorker(context, parameters) { override fun createWork(): Single<Result> { return Single.just(Result.success()) .delay(1000L, TimeUnit.MILLISECONDS) } }
Версия SleepWorkerTest, в которой тестируется RxWorker, может быть похожа на версию, в которой тестируется CoroutineWorker. Вы используете тот же TestListenableWorkerBuilder, но теперь вызываете функцию createWork из RxWorker. createWork возвращает Single, который можно использовать для проверки поведения воркера. TestListenableWorkerBuilder обрабатывает любые сложности с потоками и параллельно выполняет код исполнителя.
@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())) } } }