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()
}
}
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();
}
}
}
Чтобы протестировать этого 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()))
}
}
@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
также можно использовать для установки тегов, таких как 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"
}
}
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();
}
}
}
В 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()))
}
}
@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()));
}
}
Дополнительные сведения об 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)
}
}
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);
}
}
Версия 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()))
}
}
}
@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())));
}
}