اختبارات الدمج مع WorkManager

يوفّر WorkManager أداة work-testing تساعد في اختبار العاملين.

ضبط إعدادات

لاستخدام عنصر work-testing، أضِفه كعنصر تبعية androidTestImplementation في build.gradle.

رائع

dependencies {
    def work_version = "2.5.0"

    ...

    // optional - Test helpers
    androidTestImplementation "androidx.work:work-testing:$work_version"
}

Kotlin

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، ما يسهّل كتابة الاختبارات بشكل متزامن، بدون الحاجة إلى التعامل مع العديد من سلاسل التعليمات أو الأقفال أو المزالج.

في ما يلي مثال حول كيفية استخدام كل هذه الفئات معًا.

Kotlin


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

Java


@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.

Kotlin


class EchoWorker(context: Context, parameters: WorkerParameters)
   : Worker(context, parameters) {
   override fun doWork(): Result {
       return when(inputData.size()) {
           0 -> Result.failure()
           else -> Result.success(inputData)
       }
   }
}

Java


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 في تطبيق فعلي.

Kotlin


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

Java


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

لنكتب اختبارًا آخر يتأكّد فيه من أنّ القيمة المتوقّعة للسمة Result هي Result.failure() عندما لا تحصل EchoWorker على أي بيانات.

Kotlin


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

Java


@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.

Kotlin


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

Java


@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 مع بعض القيود.

Kotlin


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

Java


@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.

Kotlin


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

Java


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