WorkManager 提供用於測試 Worker、ListenableWorker 和 ListenableWorker 變異版 (CoroutineWorker 和 RxWorker) 的 API。
測試工作站
假設有一個如下所示的 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,因此您可以個別驗證工作站狀態。假設在休眠期間將 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" } }
在 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 可做為測試的協同程式建構工具,因此任何以非同步方式執行的程式碼都會改為平行執行。
測試 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) } }
用於測試 RxWorker 的 SleepWorkerTest 版本,似乎與測試 CoroutineWorker 的版本相似。使用相同的 TestListenableWorkerBuilder,但現在呼叫 RxWorker 的 createWork 函式。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())) } } }