The second Android 11 Developer Preview is now available, test it out and share your feedback.

Testing Worker implementation

Beginning with version 2.1.0, WorkManager provides APIs for testing Worker, ListenableWorker, and the ListenableWorker variants (CoroutineWorker and RxWorker).

Prior to version 2.1.0, to test your workers you needed to use WorkManagerTestInitHelper to initialize WorkManager. With 2.1.0, you do not need to use WorkManagerTestInitHelper if you are testing the implementation of Worker.

Testing ListenableWorker and its variants

To test a ListenableWorker or its variants (CoroutineWorker and RxWorker), use TestListenableWorkerBuilder. This builder helps build instances of ListenableWorker that can be used for the purpose of testing the Worker's business logic.

For example, suppose we need to test a CoroutineWorker which looks like this:

Kotlin

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

Java

public class SleepWorker extends ListenableWorker {
    private final ResolvableFuture<Result> mResult;
    private final Handler mHandler;
    private final Object mLock;
    private Runnable mRunnable;
    public SleepWorker(
            @NonNull Context context,
            @NonNull WorkerParameters workerParameters) {
        super(context, workerParameters);
        mHandler = new Handler(Looper.getMainLooper());
        mResult = new ResolvableFuture<>();
        mLock = new Object();
    }

    @NonNull
    @Override
    public ListenableFuture<Result> startWork() {
        mRunnable = new Runnable() {
            @Override
            public void run() {
                synchronized (mLock) {
                    mResult.set(Result.success());
                }
            }
        };

        mHandler.postDelayed(mRunnable, 1000L);
        return mResult;
    }

    @Override
    public void onStopped() {
        super.onStopped();
        if (mRunnable != null) {
            mHandler.removeCallbacks(mRunnable);
        }
        synchronized (mLock) {
            if (!mResult.isDone()) {
                mResult.set(Result.failure());
            }
        }
    }
}

To test SleepWorker, we first create an instance of the Worker using TestListenableWorkerBuilder. This builder can also be used to set tags, inputData, runAttemptCount, and so on. For details, see the TestListenableWorker reference page.

Kotlin

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

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

    @Test
    fun testSleepWorker() {
        // Kotlin code can use the TestListenableWorkerBuilder extension to
        // build the ListenableWorker
        val worker = TestListenableWorkerBuilder<SleepWorker>(context).build()
        runBlocking {
            val result = worker.doWork()
            assertThat(result, `is`(Result.success()))
        }
    }
}

Java

@RunWith(AndroidJUnit4.class)
public class SleepWorkerJavaTest {
    private Context mContext;

    @Before
    public void setUp() {
        mContext = ApplicationProvider.getApplicationContext();
    }

    @Test
    public void testSleepWorker() throws Exception {
       ListenableWorker worker =
           TestListenableWorkerBuilder.from(mContext, SleepWorker.class)
                   .build();

        Result result = worker.startWork().get();
        assertThat(result, is(Result.success()));
    }
}

Testing Workers

Let’s say we have a Worker which looks like this:

Kotlin

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

    companion object {
        const val SLEEP_DURATION = "SLEEP_DURATION"
    }

    override fun doWork(): Result {
        // Sleep on a background thread.
        val sleepDuration = inputData.getLong(SLEEP_DURATION, 1000)
        Thread.sleep(sleepDuration)
        return Result.success()
    }
}

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

To test this Worker, you can now use TestWorkerBuilder. The main difference between TestWorkerBuilder and a TestListenableWorkerBuilder is, TestWorkerBuilder lets you specify the background Executor used to run the Worker.

Kotlin

// Kotlin code can use 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 10000L)
        ).build()

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

Java


@RunWith(AndroidJUnit4.class)
public class SleepWorkerJavaTest {
    private Context mContext;
    private Executor mExecutor;

    @Before
    public void setUp() {
        mContext = ApplicationProvider.getApplicationContext();
        mExecutor = Executors.newSingleThreadExecutor();
    }

    @Test
    public void testSleepWorker() {
        Data inputData = new Data.Builder()
                .putLong("SLEEP_DURATION", 10_000L)
                .build();

        SleepWorker worker =
                (SleepWorker) TestWorkerBuilder.from(mContext,
                        SleepWorker.class,
                        mExecutor)
                        .setInputData(inputData)
                        .build();

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