WorkManager cung cấp các API để kiểm thử Worker, ListenableWorker, các biến thể của ListenableWorker (CoroutineWorker và RxWorker).
Công đoạn kiểm thử Worker
Giả sử chúng ta có Worker như sau:
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(); } } }
Để kiểm thử Worker này, bạn có thể sử dụng TestWorkerBuilder. Trình xây dựng này giúp tạo ra các thực thể của Worker có thể dùng cho mục đích kiểm thử logic kinh doanh.
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())); } }
Bạn cũng có thể sử dụng TestWorkerBuilder để đặt thẻ, chẳng hạn như inputData hoặc runAttemptCount. Nhờ đó bạn có thể xác minh trạng thái của worker một cách riêng biệt. Hãy xem xét một ví dụ, trong đó SleepWorker lấy thời lượng ngủ làm dữ liệu đầu vào thay vì là một hằng số được xác định trong worker:
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(); } } }
Trong SleepWorkerTest, bạn có thể cung cấp dữ liệu đầu vào đó cho TestWorkerBuilder để đáp ứng nhu cầu của SleepWorker.
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())); } }
Để biết thêm chi tiết về API TestWorkerBuilder, hãy xem trang đối chiếu của TestListenableWorkerBuilder, lớp cha (superclass) của TestWorkerBuilder.
Công đoạn kiểm thử ListenableWorker và các biến thể
Để kiểm thử ListenableWorker hoặc các biến thể của lớp này (CoroutineWorker và RxWorker), hãy sử dụng TestListenableWorkerBuilder.
Sự khác biệt chính giữa TestWorkerBuilder và TestListenableWorkerBuilder là TestWorkerBuilder cho phép bạn chỉ định nền mà Executor dùng để chạy Worker, trong khi TestListenableWorkerBuilder dựa vào logic tạo luồng của việc triển khai ListenableWorker.
Ví dụ, giả sử chúng ta cần kiểm thử một CoroutineWorker như sau:
class SleepWorker(context: Context, parameters: WorkerParameters) :
CoroutineWorker(context, parameters) {
override suspend fun doWork(): Result {
delay(1000L) // milliseconds
return Result.success()
}
}
Để kiểm thử SleepWorker, trước tiên chúng ta tạo một thực thể của Worker bằng cách sử dụng TestListenableWorkerBuilder, sau đó gọi hàm doWork của lớp này trong một coroutine.
@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 có tác dụng như một trình xây dựng coroutine cho việc kiểm thử. Nhờ vậy, mọi mã thực thi sẽ chạy song song thay vì thực thi không đồng bộ.
Công đoạn kiểm thử việc triển khai RxWorker cũng tương tự như công đoạn kiểm thử CoroutineWorker, vì TestListenableWorkerBuilder có thể xử lý bất kỳ lớp con nào của ListenableWorker.
Hãy cân nhắc sử dụng phiên bản SleepWorker dùng RxJava thay vì coroutine.
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); } }
Phiên bản SleepWorkerTest dùng để kiểm thử một RxWorker có thể tương tự như phiên bản đã dùng để kiểm thử một CoroutineWorker. Bạn vẫn dùng cùng một TestListenableWorkerBuilder, nhưng bây giờ lớp này sẽ gọi vào hàm createWork của RxWorker. createWork sẽ trả về Single mà bạn có thể sử dụng để xác minh hành vi của worker. TestListenableWorkerBuilder xử lý mọi sự phức tạp trong việc tạo luồng và đồng thời thực thi mã worker của bạn.
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()))); } }