اجرای تست کارگر

WorkManager APIهایی را برای آزمایش 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()
   
}
}


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();
       
}
   
}
}

برای تست این 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()))
   
}
}


@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()));
   
}
}

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"
   
}
}


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();
       
}
   
}
}

در 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()))
   
}
}


@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()));
   
}
}

برای جزئیات بیشتر در مورد TestWorkerBuilder API، به صفحه مرجع 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)
   
}
}


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);
   
}
}

نسخه‌ای از 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()))
       
}
   
}
}


@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())));
       
}
}