Worker-Implementierung testen

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

Test-Worker

Angenommen, wir haben eine Worker, die so aussieht:

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

Zum Testen dieses Worker können Sie TestWorkerBuilder verwenden. Mit diesem Builder können Sie Instanzen von Worker erstellen, mit denen die Geschäftslogik getestet werden kann.

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 = TestWorkerBuilder<SleepWorker>(
            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()));
    }
}

Mit TestWorkerBuilder können auch Tags wie inputData oder runAttemptCount festgelegt werden, sodass Sie den Worker-Status isoliert prüfen können. Nehmen wir ein Beispiel, bei dem SleepWorker eine Ruhedauer als Eingabedaten annimmt, anstatt sie im Worker als Konstante zu definieren:

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

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

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 = TestWorkerBuilder<SleepWorker>(
            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()));
    }
}

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

ListenableWorker und seine Varianten testen

Verwenden Sie zum Testen eines ListenableWorker oder seiner Varianten (CoroutineWorker und RxWorker) TestListenableWorkerBuilder. Der Hauptunterschied zwischen TestWorkerBuilder und 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öchten 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()
    }
}

Um SleepWorker zu testen, erstellen wir zuerst mit TestListenableWorkerBuilder eine Instanz des Workers und rufen dann die Funktion doWork innerhalb 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 jeder Code, der asynchron ausgeführt 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. Nehmen wir eine Version von SleepWorker, die RxJava anstelle von Koroutinen verwendet.

Kotlin


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

Eine Version von SleepWorkerTest, mit der ein RxWorker getestet wird, kann ähnlich aussehen wie die Version, mit der ein CoroutineWorker getestet wurde. Sie verwenden dasselbe TestListenableWorkerBuilder, rufen aber jetzt die createWork-Funktion von RxWorker auf. createWork gibt ein Single-Objekt zurück, mit dem Sie das Verhalten Ihres Workers prüfen können. TestListenableWorkerBuilder verarbeitet alle Threading-Komplexitäten und führt den Worker-Code parallel aus.

Kotlin


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

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