WorkManager には、Worker、ListenableWorker、ListenableWorker のバリアント(CoroutineWorker と RxWorker)をテストするための API が用意されています。
Worker のテスト
次のような 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 などのタグを設定し、Worker の状態を個別に確認することもできます。次の例では、SleepWorker が 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" } }
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())) } }
TestWorkerBuilder API について詳しくは、TestListenableWorkerBuilder(TestWorkerBuilder のスーパークラス)のリファレンス ページをご覧ください。
ListenableWorker とそのバリアントのテスト
ListenableWorker またはそのバリアント(CoroutineWorker と RxWorker)をテストするには、TestListenableWorkerBuilder を使用します。TestWorkerBuilder と TestListenableWorkerBuilder の主な違いは、TestWorkerBuilder は Worker の実行に使用されるバックグラウンド Executor を指定できるのに対し、TestListenableWorkerBuilder は ListenableWorker 実装のスレッド ロジックに依存する点です。
たとえば、次のような CoroutineWorker をテストする必要があるとします。
class SleepWorker(context: Context, parameters: WorkerParameters) : CoroutineWorker(context, parameters) { override suspend fun doWork(): Result { delay(1000L) // milliseconds return Result.success() } }
SleepWorker をテストするには、まず 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 はテストのコルーチン ビルダーとして機能し、非同期で実行されるコードは代わりに並列実行されます。
TestListenableWorkerBuilder は ListenableWorker のサブクラスを処理できるため、RxWorker 実装のテストは CoroutineWorker のテストと似ています。コルーチンではなく RxJava を使用する SleepWorker について考えてみましょう。
class SleepWorker( context: Context, parameters: WorkerParameters ) : RxWorker(context, parameters) { override fun createWork(): Single<Result> { return Single.just(Result.success()) .delay(1000L, TimeUnit.MILLISECONDS) } }
RxWorker をテストするバージョンの SleepWorkerTest は、CoroutineWorker をテストするバージョンと似ています。TestListenableWorkerBuilder を使用する点は同じです。ただし、このバージョンでは RxWorker の createWork を呼び出します。createWork は Single を返します。これを使用して、Worker の動作を確認できます。TestListenableWorkerBuilder が複雑なスレッド化を行い、Worker コードを並列実行します。
@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())) } } }