Triển khai kiểm thử Worker

WorkManager cung cấp các API để kiểm thử Worker, ListenableWorker và các biến thể của ListenableWorker (CoroutineWorkerRxWorker).

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 (CoroutineWorkerRxWorker), hãy sử dụng TestListenableWorkerBuilder. Sự khác biệt chính giữa TestWorkerBuilderTestListenableWorkerBuilderTestWorkerBuilder 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())));
        }
}