An important tool for writing quality Android apps is a suite of automated Unit Tests to test your app.
These automated tests have a number of benefits, including:
- They force you to understand the pieces of functionality you’re developing.
- Making an app testable pushes you to have a better architecture on your app.
- They reduce the amount of time you need to spend on manual regression testing.
- They allow you to do regression testing frequently — reducing bugs and catching new ones earlier.
- They give you a tool to fearlessly refactor your code since you’ll be confident you haven’t added bugs.
In this tutorial, you’ll modify a Cocktails trivia game by adding unit tests to it.
Automated testing involves several different types of testing in addition to unit testing, so first look at how unit testing fits in with other types of testing.
The Testing Pyramid
Tests you can include in your app’s test suite are categorized into three different categories:
-
UI Tests:
These tests interact with the UI of your app. They emulate the user behavior and assert UI results. These are the slowest and most expensive tests you can write because they require a device/emulator to run. On Android, the most commonly used tools for UI testing are Compose Test, Espresso, and UI Automator. -
Integration Tests:
Use these when you need to check how your code interacts with other parts of the Android framework but without the complexity of the UI. They don’t require a device/emulator to run. On Android, the most common tool for integration testing is Robolectric. -
Unit Tests:
The system under test (SUT) is one class and you focus only on it. All dependencies are considered to be working correctly (and ideally have their own unit tests :]), so they’re mocked or stubbed. These tests are the fastest and least expensive tests you can write because they don’t require a device/emulator to run. On Android, the most commonly used tools for unit testing are JUnit, Mockito, and MockK.
As a general rule, you should aim to have the following split between the test categories in your project:
- UI Tests: 10%
- Integration Tests: 20%
- Unit Tests: 70%
Because the skills needed to write Unit Tests provide the foundational skills for writing Integration and UI tests, this tutorial will focus on them.
Note: This tutorial assumes you have previous experience with developing for Android in Kotlin, and that you are familiar with using Compose and Kotlin corountines. If you’re unfamiliar with the language, have a look at this tutorial. If you’re beginning with Android, check out some of our Getting Started and other Android tutorials.
Note: This tutorial assumes you have previous experience with developing for Android in Kotlin, and that you are familiar with using Compose and Kotlin corountines. If you’re unfamiliar with the language, have a look at this tutorial. If you’re beginning with Android, check out some of our Getting Started and other Android tutorials.
Getting Started
Download the materials for this tutorial by clicking the Download Materials button at the top or bottom of the tutorial. Then, open the starter project in Android Studio Hedgehog or later.
You’ll work with a Cocktails trivia game that shows various cocktails and asks you to guess the name of them.
Build and run. Here’s what you’ll see:
The project contains a number of components, including:
- MainActivity.kt: Contains the main activity for the app.
- CocktailsComposable.kt: Contains the composables for the app.
- CocktailsViewModel.kt: The ViewModel to bind the view to the game, and data.
- Game.kt:This holds the data for the game as well as some helper methods to perform actions in the game. Located in game ▸ model.
- Question.kt: Holds data about a question and has abstract methods for answering a question. Located in game ▸ model.
- Score.kt: Class for holding the score and incrementing it when a question is answered correctly. Located in game ▸ model.
The final app will do the following:
- Load a list of cocktails from the internet.
- Generate questions from that list and store them in the
Game
object. - Retrieve the first question and present it to the user.
- Allow the user to select what the answer is to which cocktail they think it is.
- Increment the score if the user’s answer is correct.
Components You Shouldn’t Unit Test
The first thing you need to consider when testing is if a component you’re working on can’t or shouldn’t be unit tested.
If a component falls into one of these categories, it’s not a good candidate for unit testing:
- It has dependencies on the Android Subsystem.
- It has dependencies on an external component with a complex interface.
- The logic in the component can’t be moved out into another object that doesn’t have dependencies on Android components.
In the starter project, three files clearly fall into these categories:
- MainActivyt.kt: An activity is tied to the app lifecycle and Android subsystem.
- CocktailsApplication.kt: An app class has many dependencies on the Android subsystem.
The inability to unit test logic in these files is one of the reasons that good architecture patterns recommend breaking out logic into other components. As you build the functionality in your app, you’ll learn about things that make a component a good candidate to test.
Writing Your First Unit Test
Getting Context
As a first step, you’ll implement the functionality to display a question. This app uses Compose views. Open the CocktailsComposable.kt file and have a look at what it’s doing. This contains the entire interface you’ll need for your app. You’ll need to implement the logic in your viewmodel to give it the data it needs. Look in the middle of CocktailsScreen
, the first composable in the file, and you’ll see:
LaunchedEffect(Unit) { cocktailsViewModel.initGame() }
That’s the entry point for your viewmodel. Now, look up a few lines and you’ll see this:
val question = cocktailsViewModel.question.collectAsState().value
This is getting a reference to the current question in a StateFlow
from CocktailsViewModel
to use in the rest of the screen.
Now open CocktailsViewModel
. Currently, your viewmodel isn’t doing a lot, but some helpers have already been provided for you. Whenever you play a game, a new Game
object is created. Open the Game.kt file located in game ▸ model.
The two important things for your first task are your list of questions and your helper method to get the next question which you’ll need to use in your viewmodel. nextQuestion()
is currently not implemented, so you’ll start writing a unit test for this.