Implementação de testes do Worker

O WorkManager fornece APIs para testar Worker, ListenableWorker e as variantes ListenableWorker (CoroutineWorker e RxWorker).

Testar workers

Suponhamos que temos um Worker parecido com o seguinte:

class SleepWorker(context: Context, parameters: WorkerParameters) :
    Worker(context, parameters) {

    override fun doWork(): Result {
        // Sleep on a background thread.
        Thread.sleep(1000)
        return Result.success()
    }
}

Para testar Worker, você pode usar TestWorkerBuilder. Esse criador ajuda a criar instâncias do Worker que podem ser usadas com a finalidade de testar a lógica de negócios.

// 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 também pode ser usado para definir tags, como inputData ou runAttemptCount, para que você possa verificar o estado do worker isoladamente. Considere um exemplo em que SleepWorker assume uma duração de suspensão como dados de entrada, em vez de ser uma constante definida no worker:

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"
    }
}

Em SleepWorkerTest, você pode fornecer esses dados de entrada para seu TestWorkerBuilder para atender às necessidades de 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()))
    }
}

Para mais detalhes sobre a API TestWorkerBuilder, consulte a página de referência para TestListenableWorkerBuilder, a superclasse de TestWorkerBuilder.

Testar o ListenableWorker e as respectivas variantes

Para testar um ListenableWorker ou as variantes (CoroutineWorker e RxWorker ), use TestListenableWorkerBuilder. A principal diferença entre TestWorkerBuilder e um TestListenableWorkerBuilder é que TestWorkerBuilder permite que você especifique o Executor de segundo plano usado para executar o Worker, enquanto TestListenableWorkerBuilder depende da lógica de linha de execução da implementação de ListenableWorker.

Por exemplo, suponha que precisamos testar um CoroutineWorker parecido com o seguinte:

class SleepWorker(context: Context, parameters: WorkerParameters) :
    CoroutineWorker(context, parameters) {
    override suspend fun doWork(): Result {
        delay(1000L) // milliseconds
        return Result.success()
    }
}

Para testar SleepWorker, primeiro criamos uma instância do Worker usando TestListenableWorkerBuilder e, em seguida, chamamos a função doWork em uma corrotina.

@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 faz sentido como um construtor de corrotinas para seus testes, de modo que qualquer código executado de forma assíncrona é executado em paralelo.

Testar uma implementação de RxWorker é semelhante a testar CoroutineWorker, porque TestListenableWorkerBuilder pode processar qualquer subclasse de ListenableWorker. Considere uma versão de SleepWorker que use RxJava em vez de corrotinas.

class SleepWorker(
    context: Context,
    parameters: WorkerParameters
) : RxWorker(context, parameters) {
    override fun createWork(): Single<Result> {
        return Single.just(Result.success())
            .delay(1000L, TimeUnit.MILLISECONDS)
    }
}

Uma versão de SleepWorkerTest que testa um RxWorker pode ser semelhante à versão que testou um CoroutineWorker. Você usa o mesmo TestListenableWorkerBuilder, mas agora chama a função createWork do RxWorker. createWork retorna um Single que pode ser usado para verificar o comportamento do worker. TestListenableWorkerBuilder processa as complexidades de linha de execução e executa o código do worker em paralelo.

@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()))
        }
    }
}