When I first started working on Gusto’s Android app, I was surprised by the Android community’s consensus that testing is hard. Or that tests are too slow. Or that it simply isn’t worth testing the UX or visual components. Many signs point to the emulator as the cause of this testing pain.
By default, unit tests only have access to the Android SDK API without an underlying implementation. Typically, the emulator or device itself would provide this underlying implementation, but in unit tests, we don’t have access to either. Roboelectric solves this by providing an API-compatible implementation of the Android SDK, allowing us to write fast and efficient tests, without an emulator, that run in a regular unit test context.
In this blog, we will cover a few examples of how Roboelectric has helped improve Gusto’s Android testing capabilities, and how it can help you too. The examples below are impactful, slimmed down versions of tests we have right in our codebase than run on every build! Before we jump in, here are some key terms:
- View — A simple visual component, such as a text field or a button.
- Fragment — A reusable section of the app’s user experience, often a collection of views, but manages layouts, Android lifecycle events and user inputs. It resides in an activity.
- Activity — A single focused thing a user can do, almost always interacting with the user. Can contain 1 or more fragments and navigation between them and other activities.
- Intent — An abstraction representing a pending operation, such as launching a new activity or asking the user to select a photo.
- Jetpack Compose — Android’s new toolkit for building native UI without XML.
Testing non-views reliant on runtime SDKs
Android’s SDK implementations are provided at runtime and aren’t available for use during non-emulator unit tests. This means that if you’re doing something like making a helper to build a SpannableString (an Android SDK class for adding stylings to displayed Strings) in a utility function, it’s almost impossible to test. Here’s how Robolectric can help:
Testing business logic inside of views
At Gusto, we try to keep our views clean and simple, but sometimes, we need to put more complex visual logic within the view where it is used. Consider the case where we want to inform a user about their next payday. Our API provides a date value, and it’s the app’s responsibility to display “Today”, “Tomorrow”, or “In X days”. To solve this, we can compare today’s date and the server date and map the result to the correct string. While we could define this logic in a helper function, we think it belongs within the view itself. And with Robolectric, we can easily test this view logic. Here’s an example:
Testing a simple Fragment
Our Gusto Wallet app has many fragments with differing user experiences based on incoming server data. Our Pay Dashboard is a prime example of server state driving the view’s state. More concretely, if your payday is today you’ll see different messaging (like in the above example) and based on recent paystubs you may see summaries and breakdowns of year to date earnings. Here’s a simple example of how to instantiate a fragment, set up some data in the view models, and then resume your fragment for testing:
Testing Jetpack Compose
Testing your Jetpack Compose components is quick and easy as well! Again, assume a simple visual component that displays the upcoming payday as either “Today”, “Tomorrow” or “In X days”.
Robolectric has one important limitation worth noting. The framework is unable to navigate through fragments and activities. Instead, a Roboelectric test will need to assert that the Intent to move to a different fragment or activity occurred as a result.
Consider a login and two factor authentication flow each being a different fragment. After the login step succeeds, we would assert that the Intent to move to the two factor authentication step occurred. Then, we’d create a new test for the two factor authentication step (probably with some setup data for the previous login step) and assert the successful authentication.
For these cases we’ve covered above, Robolectric can help developers to quickly and effectively test visual components in an Android application. Developer hours are best spent shipping value to users and not doing manual testing. The test classes using Robolectric’s framework complete in just seconds, and give developers the ability to increase our code coverage while shipping features more quickly. Get started with Robolectric today: https://robolectric.org/getting-started/