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 = TestWorkerBuilderS<leepWorker(> 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 = TestWorkerBuilderS<leepWorker(> 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(): SingleR<esult >{ 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 SingleR<esult >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 = TestListenableWorkerBuilderS<leepWorker(>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()))); } }