Worker-Implementierung testen

WorkManager bietet APIs zum Testen von Worker, ListenableWorker und den ListenableWorker-Varianten (CoroutineWorker und RxWorker).

Worker testen

Angenommen, wir haben ein Worker, das so aussieht:

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

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

Zum Testen dieses Worker können Sie TestWorkerBuilder verwenden. Mit diesem Builder können Sie Instanzen von Worker erstellen, die zum Testen der Geschäftslogik verwendet werden können.

// 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 kann auch verwendet werden, um Tags wie inputData oder runAttemptCount festzulegen, damit Sie den Worker-Status isoliert prüfen können. Angenommen, SleepWorker verwendet eine Schlafdauer als Eingabedaten, anstatt dass sie als Konstante im Worker definiert ist:

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

In SleepWorkerTest können Sie diese Eingabedaten für TestWorkerBuilder bereitstellen, um die Anforderungen von SleepWorker zu erfüllen.

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

Weitere Informationen zur TestWorkerBuilder API finden Sie auf der Referenzseite für TestListenableWorkerBuilder, die Basisklasse von TestWorkerBuilder.

ListenableWorker und seine Varianten testen

Verwenden Sie TestListenableWorkerBuilder, um einen ListenableWorker oder seine Varianten (CoroutineWorker und RxWorker) zu testen. Der Hauptunterschied zwischen TestWorkerBuilder und einem TestListenableWorkerBuilder besteht darin, dass Sie mit TestWorkerBuilder den Hintergrund-Executor angeben können, der zum Ausführen des Worker verwendet wird, während TestListenableWorkerBuilder auf der Threading-Logik der ListenableWorker-Implementierung basiert.

Angenommen, wir müssen eine CoroutineWorker testen, die so aussieht:

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

Zum Testen von SleepWorker erstellen wir zuerst eine Instanz des Workers mit TestListenableWorkerBuilder und rufen dann die Funktion doWork in einer Koroutine auf.

@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 ist als Coroutine-Builder für Ihre Tests sinnvoll, damit Code, der asynchron ausgeführt werden würde, stattdessen parallel ausgeführt wird.

Das Testen einer RxWorker-Implementierung ähnelt dem Testen von CoroutineWorker, da TestListenableWorkerBuilder jede abgeleitete Klasse von ListenableWorker verarbeiten kann. Betrachten wir eine Version von SleepWorker, die RxJava anstelle von Koroutinen verwendet.

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

Eine Version von SleepWorkerTest, die einen RxWorker testet, kann der Version ähneln, die einen CoroutineWorker getestet hat. Sie verwenden dieselbe TestListenableWorkerBuilder, rufen aber jetzt die Funktion createWork von RxWorker auf. createWork gibt ein Single zurück, mit dem Sie das Verhalten Ihres Workers prüfen können. TestListenableWorkerBuilder übernimmt die Threading-Komplexität und führt den Worker-Code parallel aus.

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