WorkManager との統合テスト

WorkManager は、ワーカーのテストに役立つ work-testing アーティファクトを備えています。

セットアップ

work-testing アーティファクトを使用するには、build.gradle 内の androidTestImplementation 依存関係として追加します。

Groovy

 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 は、WorkManagerTestInitHelper を使用して初期化されるテストモード用 WorkManager の特別な実装を実現します。

また、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);       }   } } 

基本的なテスト

EchoWorker をテストする Android インストゥルメンテーション テストを以下に示します。重要なポイントとして、テストモードで 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 = OneTimeWorkRequestBuilderE<choWorker(>)         .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)); } 

EchoWorker が入力データを取得しなかったときに Result が想定どおり Result.failure() になるか確認する別のテストを作成しましょう。

Kotlin

 @Test @Throws(Exception::class) fun testEchoWorkerNoInput() {    // Create request    val request = OneTimeWorkRequestBuilderE<choWorker(>)        .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 インスタンスの間隔を指定できます。

初期遅延をテストする

ワーカーは、初期遅延が発生することがあります。initialDelayEchoWorker をテストする際、テストで initialDelay を待つ必要はありません。TestDriver を使用すると、制約が満たされた場合に WorkRequest の初期遅延を 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 = OneTimeWorkRequestBuilderE<choWorker(>)         .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 = OneTimeWorkRequestBuilderE<choWorker(>)         .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 = PeriodicWorkRequestBuilderE<choWorker(>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)); }