Android Testing: The Basics

Erika Tan
AndroidPub
Published in
8 min readJan 10, 2018

In some cases, writing tests for your code can be as important as writing the code itself. Testing can help ensure that your product runs the way it should, and also provides useful information for when you’re trying to debug your code. In this guide, we’ll be examining a few ways to get started in Android testing with an example project called PowerUp, an educational mobile game app for preadolescent girls created by the Systers Community. Since this is an open source project, you can contribute to PowerUp on GitHub if you’re interested after reading this guide (remember to contribute to the GSoC17 branch, not develop)!

Test types

Android Studio provides source code directories for two tests: local unit tests and instrumented tests. Local unit tests target the smallest individual parts (“units”) of your software and are located at module-name/src/test/java/. You can see this in the picture below (it’s highlighted in green just above the “assets” folder).

Project structure and test location for PowerUp

For PowerUp, there are a few unit tests included already, each of which runs tests for a separate class. Executing these tests takes a significantly lower amount of time than using an emulator, since unit tests run on the Java Virtual Machine (JVM). Libraries such as Robolectric and Mockito may be used to write unit tests — PowerUp uses Robolectric to check whether its functionalities are working properly for multiple classes. Below is a small snapshot of one of PowerUp’s unit tests called MinesweeperGameTests, which tests different aspects of a class called MinesweeperGameActivity.

MinesweeperGameTests.java

Since this is a unit test, it focuses on a single class. It also takes a short time to run: all you have to do is right-click on the test you want to execute, press “Run ‘ClassName’”, and wait for the magic to happen!

Right-click and run to see your test at work.
Results output after running MinesweeperGameTests.java

As opposed to unit tests which minimize execution time, instrumented tests run on emulators and hardware devices, making them take a little longer to run. Instrumented tests are used for testing the integration of the app; in other words, these tests check how different modules interact with each other. Instrumented tests can also be used for functional UI testing since they have access to Android components and the life cycle of the application. These tests are located at module-name/src/androidTest/java/. PowerUp currently does not have any completed instrumented tests.

Build variants

Build variants, or “product flavors”, are different versions of your app that can have different features. The most common example of using build variants would be to have a free flavor and a paid flavor. The free version of the app may only have part of the content that the paid version has. Android Studio has a small section for navigating the build variants of your project on the lower left side. Since the current version of PowerUp does not have flavors, the only variants that show up in the menu are “debug” and “release”, but adding flavors to the .gradle file will result in a Build Variants menu shown below.

Build Variants menu

To configure build variants for your own project, go to your build.gradle file and add in the following lines of code, substituting in your own names for the product flavors as needed:

android {
...
defaultConfig {...}
buildTypes {...}
productFlavors {
free {
applicationIdSuffix ".free"
versionNameSuffix "-free"
}
paid {
applicationIdSuffix ".paid"
versionNameSuffix "-paid"
}
}
}

Running unit tests from the command line

You may want to run your tests from the command line instead of doing it in Android Studio directly. To do this, you can either run tests with Gradle or ADB. The table below is a great way of organizing the type of test that you need to run, along with how to run it.

There’s also a way to test specific build variants using the command line: simply insert the variant name into either command. For local unit tests, use ./gradlew testVariantNameUnitTest, and for instrumented tests, use .gradlew connectedVariantnameAndroidTest. If you’re trying to target specific tests from your project, use the --tests flag in the command line to accomplish this. For instance, to run a test called sampleTestMethod for one of your build variants, this line may be used: .gradlew testVariantNameUnitTest --tests *.sampleTestMethod

After the test finishes execution, Gradle will save the results to the build/ directory. An important thing to keep in mind, however, is that this will happen for each module that you test. If you’re running tests across multiple modules, and you want to combine the test results into one report, add this line of code into your build.gradle file: apply plugin: 'android-reporting'

Then, add mergeAndroidReports after the ./gradlew test or ./gradlew connectedAndroidTest command. You can add the —-continue flag if you want to ignore failed tests during execution: ./gradlew test mergeAndroidReports --continue

To use ADB in the command line to run your tests, simply start an adb shell and call the am instrument. The following line of code is an example of how you can do this in your command line: adb shell am instrument — w <test_package_name>/<runner_class>

Using Mockito in unit tests

At some point during your journey in testing, you may find it tedious to keep writing test stubs manually. A mocking framework may help you solve this problem by making it faster and easier to write stubs. Mockito is one such framework that makes your tests easier to read and produces simple verification errors. But what do we mean by “mocking”? Basically, a mock object is a dummy implementation for a class and is used for testing the results of calling certain methods. To add Mockito to your project, add testCompile ‘org.mockito:mockito-core:2.7.22 to your dependencies in build.gradle.

UI Tests

UI tests are a way to measure how your app handles user interaction. You can write UI tests using frameworks such as UI Automator or Espresso. Espresso has a really cool functionality that lets you record your interactions with your app on an emulator or hardware device, then generates the test code for you! We can see this in action by creating an example test with PowerUp. Of course, in order to configure Espresso, you’ll have to add androidTestCompile ‘com.android.support.test.espresso:espresso-core:2.2.2' to your dependencies first. But once that’s done, click on “Record Espresso Test” under the Run menu.

Start recording an Espresso test

Select an emulator you would like to use from your available menu, then hit “OK”. This will create two screens: one for your emulator, and one for the Espresso Test Recorder UI.

Choosing an emulator for your Espresso test
Emulator and Test Recorder UI

The Test Recorder will now run your app in debug mode. Now you can test your app’s UI by interacting with your emulator as one of your users would: pushing buttons, typing into text fields, swiping across the screen, or anything else that your app may be compatible with. All of these actions will appear in the Test Recorder UI; for example, I’ve tapped on the “New Game” button to create a new avatar, which then brings me to the avatar customization screen.

Automated user interaction recording

The “Add Assertion” button in the Test Recorder window may be used for performing assertions on specific views. With this option, you can check if a view exists, doesn’t exist, or if it contains some certain text. When you’re all done, hit “OK” and name your test. Espresso then does all of the hard work and writes the code for you! But of course, if you need to make manual edits to the code, you can do that directly in the generated file, too .

ExampleTest.java

Small, medium, and large tests

There’s no doubt about it — all of this testing jargon can get pretty confusing. Fortunately, the developers at Google came up with a naming convention for their tests that describes each of their tests by size: small, medium, and large. A small test is similar to a unit test: it only interacts with the specified class. Medium tests should have access to the file system and database of the machine they’re running on. The main difference between medium and large tests is that large tests can use external systems and networks. The amount of time it takes to run each test also corresponds to the name of the test: small tests should take a significantly lower amount of time to execute than medium and large tests. Annotations for these types of tests can also be useful for documenting your code, such as putting a @SmallTest annotation above one of your test stubs.

How do I know when I have enough tests?

You should write enough tests to make sure that all of your app features work well by themselves and together. But how much is “enough”? That’s where the built-in code coverage tool for Android Studio will be very useful. It checks the percentages of your classes and lines of code that are covered by tests you’ve written, as well as the classes that you still need to write tests for. To use this powerful tool, right-click on the test or testing folder that you want to run. Then, click on “Run ‘Tests in ‘test’’ with Coverage” which is one of the options in the pop-up menu.

Running tests with code coverage

A new window will appear that tells you the exact percentage of classes and code you have covered. Also, you’ll notice that in your project sidebar, it’ll tell you how many lines and methods are covered in each class!

Code coverage for PowerUp
Code coverage for each class

It’s time to jump into the world of testing

Now that you know the basics about testing for Android, I hope this guide will continue to help you in writing and conducting tests for your app, and maybe even inspire you to contribute to PowerUp. In addition, there are many other great testing frameworks for you to explore that haven’t been explained in this article, and even more to discover about the world of programming itself — not just testing! With that being said, take every opportunity to cherish what you’ve learned — I certainly did while writing this article. Happy Coding!

--

--