Testing Android Architecture Components
Learn how to test the Architecture Components library included in the Android Jetpack suite released in 2017 by Google’s Android Team. By Enzo Lizama.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Testing Android Architecture Components
20 mins
- Getting Started
- What Are Android Architecture Components?
- Structuring Your Tests
- Testing on Android
- Testing ViewModel and LiveData
- Verifying onChanged() Events
- Asserting LiveData Values
- Testing DAO
- Testing Room Migrations
- Creating Your Room Migration Test
- Testing Incremental Migration
- Testing All Migrations
- Where to Go From Here?
At the 2017 Google I/O event, the Android team released Android Jetpack, a suite of libraries to help developers follow best practices, reduce boilerplate code and write code that works consistently across Android versions and devices.
Since then, Android developers have adopted those libraries to increase their productivity and their code quality, but testing using the new libraries is complicated. In this tutorial, you’ll learn how to test Android Jetpack’s Architecture Components libraries.
You’ll take a deep look into Android Architecture Components testing techniques by working on RWQuotes, a simple app that allows you to create and read famous quotes in local storage. In the process, you’ll learn about:
- Basic testing concepts
- The testing tools available for Android
- How to test ViewModel and LiveData
- Testing Room database operations and migrations
Now, you’ll get started by taking a look at the project.
Getting Started
Download the materials for this tutorial by clicking the Download Materials button at the top or bottom of this tutorial page. Extract the ZIP file and open the start project in Android Studio. Please check that you have the latest stable version.
Once the Gradle tasks complete, build and run and you’ll see RWQuotes’ home screen.
Here’s a look at the project structure:
Inside the data folder, you’ll find:
-
Quote.kt: A data class that represents the
entity
you’ll store in the database. -
QuoteDao.kt: An abstract class where you define the database interactions with annotations like
@Query
,@Insert
,@Delete
and@Update
. - Migrations.kt: Stores the migration values from different versions.
- RWQuotesDatabase.kt: Creates the Room database, allows you to get the instance for that, and manages the migrations and the prepopulated data.
- QuoteRepositoryImpl.kt: Implements QuoteRepository.kt and uses QuoteDao.kt to perform the CRUD operations.
Next, you have ui, which stores everything related to the views and user interactions. Within that folder, you’ll find >ui/viewmodel, which contains everything related to LiveData
and ViewModel
. The data request for QuoteRepository.kt is here.
Finally, you’ll see RWQuoteApplication.kt, which is an application class that initializes the debugger when you’re in develop mode.
So now that you have a good idea of how the project is set up, it’s time to take a moment to understand the architecture components you’ll work with throughout this tutorial.
What Are Android Architecture Components?
Android architecture components are a collection of libraries that help you design robust, testable and maintainable apps.
In this tutorial, you’ll use the following classes to manage your UI component lifecycle and handle data persistence:
- LiveData helps you build data objects that notify views when the underlying database changes.
- ViewModel stores UI-related data that isn’t destroyed on app rotations.
- Room is an SQLite object mapping library. Use it to avoid boilerplate code and easily convert SQLite table data to Java objects. Room provides compile time checks of SQLite statements and can return RxJava, Flowable and LiveData observables.
Structuring Your Tests
Users interact with apps on a variety of levels, from pressing a button to downloading information onto their device. To make sure that every function works, you should test a variety of use cases and interactions as you iteratively develop your app.
The image below shows the Testing Pyramid, showing the three categories of tests you should include in your app’s test suite:
As you work up the pyramid from small tests to large tests, each test increases fidelity but also increases in execution time and effort to maintain and debug. Therefore, you should write more unit tests than integration tests, and more integration tests than UI tests.
Testing on Android
By default, when you create a new Android project on Android Studio, it will create two folders for testing: androidTest and test. androidTest contains tests that run on real or virtual devices. These include integration tests, end-to-end tests and other tests where the JVM alone cannot validate your app’s functionality.
test
contains tests that run on your local machine, such as unit tests.
There are many libraries that simplify the testing process. Here are the most popular for Android development testing:
- JUnit: The most popular and widely-used unit testing framework for Java.
- Mockito: Helps you configure mock objects to return specific values when you invoke them.
- Espresso: Use Espresso to write concise, beautiful and reliable Android UI tests.
- Robolectric: A framework that brings fast and reliable unit tests to Android. Tests run inside the JVM on your workstation in seconds.
If you’re unfamiliar with them, check out these tutorials:
- Android Unit Testing with Mockito
- Espresso Testing and Screen Robots: Getting Started
- Test-Driven Development Tutorial for Android: Getting Started
For this tutorial, you’ll make unit tests for ViewModel
and LiveData
and integration tests for the Room database. These tests have something in common: You’ll use a special Rule, InstantTaskExecutorRule
, to make architecture component testing easy as possible.
Here’s how it looks:
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
This is a JUnit test rule that swaps the background executor used by the architecture components with a different one that executes each task synchronously. This rule is commonly used for host-side tests that use architecture components. You’ll use this rule going forward to make it easier to create tests.
Now that you know some useful concepts about Android testing, it’s time to get started creating your test.
Testing ViewModel and LiveData
Start by creating a new test class by right-clicking on the test package and selecting New ▸ Kotlin File/Class. Name the new class QuotesViewModelTest
and add the following to it:
// 1
@RunWith(AndroidJUnit4::class)
class QuotesViewModelTest {
// 2
@Mock
private lateinit var viewModel: QuotesViewModel
@Mock
private lateinit var isLoadingLiveData: LiveData<Boolean>
@Mock
private lateinit var observer: Observer<in Boolean>
// 3
@get:Rule
var instantExecutorRule = InstantTaskExecutorRule()
// 4
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
viewModel = spy(QuotesViewModel(ApplicationProvider.getApplicationContext(),
QuotesRepositoryImpl(ApplicationProvider.getApplicationContext())))
isLoadingLiveData = viewModel.dataLoading
}
// Your tests go here ...
}
Before starting to create your tests, you need to set everything up to make the tests work as expected. So, here’s what you do in the code above:
- You need to annotate the class to run with
AndroidJUnit4
, which is a cross-environment JUnit4 runner for Android tests. This implementation will delegate to the appropriate runner based on the value the build system provides. - Mark the necessary fields as
@Mock
to allow shorthand mock creation and minimize repetitive mock creation code. - Define the
InstantTaskExecutorRule
to run any executors synchronously - Finally, in the
setup
function marked as@Before
, you initialize the mocks for the tests and assign values for others. The following tests have to go below this code.
Next, you’ll write a test that verifies that the progress state triggers within your ViewModel.