آزمایش کردن پیاده‌سازی Worker

WorkManager میاناهای برنامه‌سازی کاربردی‌ای برای آزمایش کردن Worker، ListenableWorker، و متغیرهای ListenableWorker (CoroutineWorker و RxWorker) ارائه می‌دهد.

آزمایش کردن کارگران

فرض کنید یک 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 مدت زمان خواب را به‌عنوان داده ورودی دریافت می‌کند، به‌جای اینکه این مقدار به‌عنوان یک ثابت در 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، به صفحه مرجع TestListenableWorkerBuilder، ابرکلاس TestWorkerBuilder مراجعه کنید.

آزمایش کردن ListenableWorker و انواع آن

برای آزمایش ListenableWorker یا انواع آن (CoroutineWorker و RxWorker)، از TestListenableWorkerBuilder استفاده کنید. تفاوت اصلی بین TestWorkerBuilder و TestListenableWorkerBuilder این است که TestWorkerBuilder به شما امکان می‌دهد Executor پس‌زمینه استفاده‌شده برای اجرای Worker را مشخص کنید، درحالی‌که TestListenableWorkerBuilder به منطق رشته‌ای پیاده‌سازی ListenableWorker متکی است.

برای مثال، فرض کنید باید CoroutineWorker را آزمایش کنیم که به این شکل است:

class SleepWorker(context: Context, parameters: WorkerParameters) :
    CoroutineWorker(context, parameters) {
    override suspend fun doWork(): Result {
        delay(1000L) // milliseconds
        return Result.success()
    }
}

برای آزمایش SleepWorker، ابتدا نمونه‌ای از Worker را بااستفاده از 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)
    }
}

نسخه‌ای از SleepWorkerTest که RxWorker را آزمایش می‌کند ممکن است شبیه به نسخه‌ای باشد که CoroutineWorker را آزمایش کرده است. از همان TestListenableWorkerBuilder استفاده می‌کنید اما اکنون تابع createWork مربوط به RxWorker را فراخوانی می‌کنید. 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()))
        }
    }
}