WorkManager, Dagger and Testing

Sebastiano Gottardo
3 min readNov 3, 2021

--

A concise and laser-sharp addendum.

It’s been a few years now since Google introduced WorkManager as an API to schedule asynchronous work, and it’s been a great addition to Jetpack’s already impressive set of libraries. Pair this with a fantastic IDE integration that allows developers to inspect background tasks, and you got yourself an invaluable tool at your disposal.

At Blinkist, our previous task management library has served us well for many years, but it was discontinued many moons ago and it was proving harder and harder to maintain. For this reason, we only recently decided to adopt WorkManager to handle our background operations, but as it’s pretty common for codebases of non trivial complexity, the official documentation was proving to be quite helpful but also insufficient to provide an answer to all our questions.

A quick search surfaced this awesome series of articles about WorkManager written by Pietro Maggi. These articles go more in-depth and explore many, more advanced use cases that better suited our situation. We quickly realized that we would have to go all in and use many of the more advanced WorkManager features, like on-demand initialization and using custom WorkerFactory classes together with Dagger, our DI framework of choice.

After a few usual frustrations, we got our integration up and running, and WorkManager was working as expected. Happy days!

But wait, what about testing? 🤔

Testing WorkManager with a custom WorkerFactory

The official documentation is pretty thorough when it comes to explaining how WorkManager can be tested, but suffers from the same issue as not covering the more advanced use cases. One article in the series I mentioned before touches base on testing, but when it comes to custom factories, there is no mention of it.

For the sake of simplicity, let’s assume we have a custom WorkerFactory that doesn’t need to delegate, but singlehandedly handles the creation of workers:

💡 There is one small thing to note here: if you only have one worker in your custom WorkerFactory you might be tempted to change the return type to ListenableWorker, thereby removing the nullability. Don’t do it! Returning null is an expected behavior that the WorkerFactory base class uses to fallback to reflection in case no custom factories can handle that specific worker type. For the curious, here’s the source code.

Back to our example then. We have our custom WorkerFactory in place, and we instructed WorkManager to use that first when creating its Configuration instance.

Now, we want to test that BackgroundSyncWorker performs its task correctly and without errors. Documentation points us to TestWorkerBuilder, so we could put together something like this:

However, TestWorkerBuilder has no notion of the fact that CustomWorkerFactory exists, and running this code would lead to an error: the base WorkerFactory class would try to instantiate BackgroundSyncWorker using reflection, but since this worker has an extra construction parameter (an instance of SyncService), this operation will fail.

Thankfully, TestWorkerBuilder has a handy method to make up for this: setWorkerFactory! Our code then simply becomes:

That’s it! You can now enjoy testing workers with custom WorkerFactory classes 🙌

Conclusion

I hope this article was helpful with the few of you who might incur into this situation!

Feel free to let me know what you think on Twitter 🐦

--

--