Test dell'implementazione del worker

WorkManager fornisce le API per i test di Worker, ListenableWorker e ListenableWorker varianti (CoroutineWorker) e RxWorker).

Worker per i test

Supponiamo di avere un Worker simile a questo:

Kotlin

class SleepWorker(context: Context, parameters: WorkerParameters) :
    Worker(context, parameters) {

    override fun doWork(): Result {
        // Sleep on a background thread.
        Thread.sleep(1000)
        return Result.success()
    }
}

Java

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

Per testare questo Worker, puoi usare TestWorkerBuilder Questo aiuta a creare istanze di Worker che possono essere utilizzate ai fini di testare la logica di business.

Kotlin

// 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 = TestWorkerBuilderS<leepWorker(>
            context = context,
            executor = executor
        ).build()

        val result = worker.doWork()
        assertThat(result, `is`(Result.success()))
    }
}

Java

@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 può essere utilizzato anche per impostare tag, ad esempio inputData o runAttemptCount, in modo da poter verificare lo stato del worker in modo isolato. Prendi in considerazione un esempio in cui SleepWorker prende la durata del sonno come dati di input invece di essere una costante definita nel worker:

Kotlin

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

Java

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

In SleepWorkerTest, puoi fornire questi dati di input al tuo TestWorkerBuilder per soddisfare le esigenze di SleepWorker.

Kotlin

// 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 = TestWorkerBuilderS<leepWorker(>
            context = context,
            executor = executor,
            inputData = workDataOf("SLEEP_DURATION" to 1000L)
        ).build()

        val result = worker.doWork()
        assertThat(result, `is`(Result.success()))
    }
}

Java

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

Per maggiori dettagli sull'API TestWorkerBuilder, consulta la pagina di riferimento per TestListenableWorkerBuilder, la superclasse TestWorkerBuilder.

Test di ListenableWorker e delle sue varianti

Per testare un elemento ListenableWorker o la relativa varianti (CoroutineWorker e RxWorker), utilizza TestListenableWorkerBuilder. La differenza principale tra TestWorkerBuilder e a TestListenableWorkerBuilder è che TestWorkerBuilder ti consente di specificare lo sfondo Executor utilizzato eseguire Worker, mentre TestListenableWorkerBuilder si basa della logica di thread dell'implementazione di ListenableWorker.

Ad esempio, supponiamo di dover testare un CoroutineWorker che ha questo aspetto:

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

Per testare SleepWorker, creiamo prima un'istanza del worker utilizzando TestListenableWorkerBuilder e quindi richiamare la relativa funzione doWork all'interno di un coroutine.

@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 ha senso come strumento per la creazione di coroutine per i tuoi test, in modo che qualsiasi codice che verrebbe eseguito in modo asincrono, viene eseguito in parallelo.

Il test di un'implementazione RxWorker è simile al test di CoroutineWorker, poiché TestListenableWorkerBuilder può gestire qualsiasi sottoclasse di ListenableWorker. Prendi in considerazione una versione di SleepWorker che utilizzi RxJava anziché coroutine.

Kotlin

class SleepWorker(
    context: Context,
    parameters: WorkerParameters
) : RxWorker(context, parameters) {
    override fun createWork(): SingleR<esult >{
        return Single.just(Result.success())
            .delay(1000L, TimeUnit.MILLISECONDS)
    }
}

Java

public class SleepWorker extends RxWorker {
    public SleepWorker(@NonNull Context appContext, 
@NonNull WorkerParameters workerParams) {
        super(appContext, workerParams);
    }

    @NonNull
    @Override
    public SingleR<esult >createWork() {
        return Single.just(Result.success())
                .delay(1000L, TimeUnit.MILLISECONDS);
    }
}

Una versione di SleepWorkerTest che esegue il test di un RxWorker può essere simile alla che ha testato un CoroutineWorker. Utilizzi lo stesso TestListenableWorkerBuilder ma ora chiama createWork di RxWorker personalizzata. createWork restituisce un Single che puoi utilizzare per verificare il comportamento del worker. TestListenableWorkerBuilder gestisce tutti i thread complessità ed esegue il codice worker in parallelo.

Kotlin

@RunWith(AndroidJUnit4::class)
class SleepWorkerTest {
    private lateinit var context: Context

    @Before
    fun setUp() {
        context = ApplicationProvider.getApplicationContext()
    }

    @Test
    fun testSleepWorker() {
        val worker = TestListenableWorkerBuilderS<leepWorker(>context).build()
        worker.createWork().subscribe { result -
>            assertThat(result, `is`(Result.success()))
        }
    }
}

Java

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