WorkManager یک
ساخته work-testing ارائه میدهد که به آزمایش کردن workerهای شما کمک میکند.
راهاندازی
برای استفاده از مصنوع work-testing، آن را بهعنوان وابستگی androidTestImplementation در build.gradle اضافه کنید.
شیک
dependencies { def work_version = "2.5.0" ... // optional - Test helpers androidTestImplementation "androidx.work:work-testing:$work_version" }
کاتلین
dependencies { val work_version = "2.4.0" ... // optional - Test helpers androidTestImplementation("androidx.work:work-testing:$work_version") }
برای اطلاعات بیشتر درباره افزودن وابستگیها، به بخش «اعلام وابستگیها» در یادداشتهای انتشار WorkManager مراجعه کنید.
مفاهیم
work-testing پیادهسازی ویژهای از WorkManager برای حالت آزمایشی ارائه میدهد،
که بااستفاده از
WorkManagerTestInitHelper مقداردهی اولیه میشود.
ساخته work-testing همچنین یک
SynchronousExecutor
ارائه میدهد که نوشتن آزمایشها را بهصورت همگام آسانتر میکند، بدون اینکه نیاز باشد
با چندین رشته، قفل، یا لچ سروکار داشته باشید.
در اینجا مثالی از نحوه استفاده از همه این کلاسها باهم آورده شده است.
کاتلین
@RunWith(AndroidJUnit4::class) class BasicInstrumentationTest { @Before fun setup() { val context = InstrumentationRegistry.getTargetContext() val config = Configuration.Builder() .setMinimumLoggingLevel(Log.DEBUG) .setExecutor(SynchronousExecutor()) .build() // Initialize WorkManager for instrumentation tests. WorkManagerTestInitHelper.initializeTestWorkManager(context, config) } }
جاوا
@RunWith(AndroidJUnit4.class) public class BasicInstrumentationTest { @Before public void setup() { Context context = InstrumentationRegistry.getTargetContext(); Configuration config = new Configuration.Builder() .setMinimumLoggingLevel(Log.DEBUG) .setExecutor(new SynchronousExecutor()) .build(); // Initialize WorkManager for instrumentation tests. WorkManagerTestInitHelper.initializeTestWorkManager( context, config); } }
آزمایشهای ساختاربندی
اکنون که WorkManager در حالت آزمایشی مقداردهی اولیه شده است، آمادهاید تا کارگران خود را آزمایش کنید.
فرض کنید یک EchoWorker دارید که انتظار دارد مقداری inputData دریافت کند و بهسادگی
ورودی خود را در outputData کپی (تکرار) میکند.
کاتلین
class EchoWorker(context: Context, parameters: WorkerParameters) : Worker(context, parameters) { override fun doWork(): Result { return when(inputData.size()) { 0 -> Result.failure() else -> Result.success(inputData) } } }
جاوا
public class EchoWorker extends Worker { public EchoWorker(Context context, WorkerParameters parameters) { super(context, parameters); } @NonNull @Override public Result doWork() { Data input = getInputData(); if (input.size() == 0) { return Result.failure(); } else { return Result.success(input); } } }
آزمایشهای پایه
در زیر یک آزمایش ابزارگری Android وجود دارد که EchoWorker را آزمایش میکند. نکته اصلی
در اینجا این است که آزمایش EchoWorker در حالت آزمایشی بسیار شبیه به نحوه
استفاده از EchoWorker در برنامه واقعی است.
کاتلین
@Test @Throws(Exception::class) fun testSimpleEchoWorker() { // Define input data val input = workDataOf(KEY_1 to 1, KEY_2 to 2) // Create request val request = OneTimeWorkRequestBuilder<EchoWorker>() .setInputData(input) .build() val workManager = WorkManager.getInstance(applicationContext) // Enqueue and wait for result. This also runs the Worker synchronously // because we are using a SynchronousExecutor. workManager.enqueue(request).result.get() // Get WorkInfo and outputData val workInfo = workManager.getWorkInfoById(request.id).get() val outputData = workInfo.outputData // Assert assertThat(workInfo.state, `is`(WorkInfo.State.SUCCEEDED)) assertThat(outputData, `is`(input)) }
جاوا
@Test public void testSimpleEchoWorker() throws Exception { // Define input data Data input = new Data.Builder() .put(KEY_1, 1) .put(KEY_2, 2) .build(); // Create request OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(EchoWorker.class) .setInputData(input) .build(); WorkManager workManager = WorkManager.getInstance(getApplicationContext()); // Enqueue and wait for result. This also runs the Worker synchronously // because we are using a SynchronousExecutor. workManager.enqueue(request).getResult().get(); // Get WorkInfo and outputData WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); Data outputData = workInfo.getOutputData(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.SUCCEEDED)); assertThat(outputData, is(input)); }
بیایید آزمایش دیگری بنویسیم که مطمئن شویم وقتی EchoWorker هیچ داده ورودیای دریافت نمیکند،
Result موردانتظار Result.failure() است.
کاتلین
@Test @Throws(Exception::class) fun testEchoWorkerNoInput() { // Create request val request = OneTimeWorkRequestBuilder<EchoWorker>() .build() val workManager = WorkManager.getInstance(applicationContext) // Enqueue and wait for result. This also runs the Worker synchronously // because we are using a SynchronousExecutor. workManager.enqueue(request).result.get() // Get WorkInfo val workInfo = workManager.getWorkInfoById(request.id).get() // Assert assertThat(workInfo.state, `is`(WorkInfo.State.FAILED)) }
جاوا
@Test public void testEchoWorkerNoInput() throws Exception { // Create request OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(EchoWorker.class) .build(); WorkManager workManager = WorkManager.getInstance(getApplicationContext()); // Enqueue and wait for result. This also runs the Worker synchronously // because we are using a SynchronousExecutor. workManager.enqueue(request).getResult().get(); // Get WorkInfo WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.FAILED)); }
شبیهسازی محدودیتها، تأخیرها، و کارهای دورهای
WorkManagerTestInitHelper نمونهای از
TestDriver را دراختیارتان قرار میدهد که میتوان از آن
برای شبیهسازی تأخیر اولیه، شرایطی که محدودیتها برای
نمونههای ListenableWorker برآورده میشوند، و فاصلههای زمانی برای نمونههای
PeriodicWorkRequest استفاده کرد.
آزمایش تأخیرهای اولیه
کارگران ممکن است تأخیرهای اولیه داشته باشند. برای آزمایش EchoWorker با initialDelay،
بهجای اینکه منتظر initialDelay در آزمایشتان بمانید، میتوانید از
TestDriver استفاده کنید تا تأخیر اولیه درخواست کار را بهعنوان برآوردهشده بااستفاده از
setInitialDelayMet علامتگذاری کنید.
کاتلین
@Test @Throws(Exception::class) fun testWithInitialDelay() { // Define input data val input = workDataOf(KEY_1 to 1, KEY_2 to 2) // Create request val request = OneTimeWorkRequestBuilder<EchoWorker>() .setInputData(input) .setInitialDelay(10, TimeUnit.SECONDS) .build() val workManager = WorkManager.getInstance(getApplicationContext()) // Get the TestDriver val testDriver = WorkManagerTestInitHelper.getTestDriver() // Enqueue workManager.enqueue(request).result.get() // Tells the WorkManager test framework that initial delays are now met. testDriver.setInitialDelayMet(request.id) // Get WorkInfo and outputData val workInfo = workManager.getWorkInfoById(request.id).get() val outputData = workInfo.outputData // Assert assertThat(workInfo.state, `is`(WorkInfo.State.SUCCEEDED)) assertThat(outputData, `is`(input)) }
جاوا
@Test public void testWithInitialDelay() throws Exception { // Define input data Data input = new Data.Builder() .put(KEY_1, 1) .put(KEY_2, 2) .build(); // Create request OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(EchoWorker.class) .setInputData(input) .setInitialDelay(10, TimeUnit.SECONDS) .build(); WorkManager workManager = WorkManager.getInstance(myContext); // Get the TestDriver TestDriver testDriver = WorkManagerTestInitHelper.getTestDriver(); // Enqueue workManager.enqueue(request).getResult().get(); // Tells the WorkManager test framework that initial delays are now met. testDriver.setInitialDelayMet(request.getId()); // Get WorkInfo and outputData WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); Data outputData = workInfo.getOutputData(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.SUCCEEDED)); assertThat(outputData, is(input)); }
محدودیتهای آزمایشی
TestDriver همچنین میتواند برای علامتگذاری محدودیتها بهعنوان برآوردهشده بااستفاده از
setAllConstraintsMet استفاده شود. در اینجا مثالی از نحوه آزمایش Worker
با محدودیتها آورده شده است.
کاتلین
@Test @Throws(Exception::class) fun testWithConstraints() { // Define input data val input = workDataOf(KEY_1 to 1, KEY_2 to 2) val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build() // Create request val request = OneTimeWorkRequestBuilder<EchoWorker>() .setInputData(input) .setConstraints(constraints) .build() val workManager = WorkManager.getInstance(myContext) val testDriver = WorkManagerTestInitHelper.getTestDriver() // Enqueue workManager.enqueue(request).result.get() // Tells the testing framework that all constraints are met. testDriver.setAllConstraintsMet(request.id) // Get WorkInfo and outputData val workInfo = workManager.getWorkInfoById(request.id).get() val outputData = workInfo.outputData // Assert assertThat(workInfo.state, `is`(WorkInfo.State.SUCCEEDED)) assertThat(outputData, `is`(input)) }
جاوا
@Test public void testWithConstraints() throws Exception { // Define input data Data input = new Data.Builder() .put(KEY_1, 1) .put(KEY_2, 2) .build(); // Define constraints Constraints constraints = new Constraints.Builder() .setRequiresDeviceIdle(true) .build(); // Create request OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(EchoWorker.class) .setInputData(input) .setConstraints(constraints) .build(); WorkManager workManager = WorkManager.getInstance(myContext); TestDriver testDriver = WorkManagerTestInitHelper.getTestDriver(); // Enqueue workManager.enqueue(request).getResult().get(); // Tells the testing framework that all constraints are met. testDriver.setAllConstraintsMet(request.getId()); // Get WorkInfo and outputData WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); Data outputData = workInfo.getOutputData(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.SUCCEEDED)); assertThat(outputData, is(input)); }
درحال آزمایش کار تناوبی
TestDriver همچنین setPeriodDelayMet را نشان میدهد که میتوان از آن برای
نشان دادن تکمیل شدن فاصله استفاده کرد. در اینجا نمونهای از
استفاده از setPeriodDelayMet آورده شده است.
کاتلین
@Test @Throws(Exception::class) fun testPeriodicWork() { // Define input data val input = workDataOf(KEY_1 to 1, KEY_2 to 2) // Create request val request = PeriodicWorkRequestBuilder<EchoWorker>(15, MINUTES) .setInputData(input) .build() val workManager = WorkManager.getInstance(myContext) val testDriver = WorkManagerTestInitHelper.getTestDriver() // Enqueue and wait for result. workManager.enqueue(request).result.get() // Tells the testing framework the period delay is met testDriver.setPeriodDelayMet(request.id) // Get WorkInfo and outputData val workInfo = workManager.getWorkInfoById(request.id).get() // Assert assertThat(workInfo.state, `is`(WorkInfo.State.ENQUEUED)) }
جاوا
@Test public void testPeriodicWork() throws Exception { // Define input data Data input = new Data.Builder() .put(KEY_1, 1) .put(KEY_2, 2) .build(); // Create request PeriodicWorkRequest request = new PeriodicWorkRequest.Builder(EchoWorker.class, 15, MINUTES) .setInputData(input) .build(); WorkManager workManager = WorkManager.getInstance(myContext); TestDriver testDriver = WorkManagerTestInitHelper.getTestDriver(); // Enqueue and wait for result. workManager.enqueue(request).getResult().get(); // Tells the testing framework the period delay is met testDriver.setPeriodDelayMet(request.getId()); // Get WorkInfo and outputData WorkInfo workInfo = workManager.getWorkInfoById(request.getId()).get(); // Assert assertThat(workInfo.getState(), is(WorkInfo.State.ENQUEUED)); }