Android: Testing with Robolectric
Brings fast and reliable unit tests to Android with Robolectric.

Senior Android Engineer from Bangladesh. Love to contribute in Open-Source. Indie Music Producer.
Search for a command to run...
Brings fast and reliable unit tests to Android with Robolectric.

Senior Android Engineer from Bangladesh. Love to contribute in Open-Source. Indie Music Producer.
No comments yet. Be the first to comment.
A practical guide to choosing the right coroutine primitive for your Android/Kotlin projects

This guide explains what Channels are, when to use them, how to use them correctly, and when NOT to use them — in simple, professional language. 1. What problem do Channels solve? In Kotlin coroutines, you often have multiple coroutines running at t...

Learn how to build preview-safe ViewModels in Jetpack Compose using Hilt.

HandlerInterceptor vs Filter in Spring Boot: A Practical Guide with JNDI Injection Prevention

Simple In-Memory Caching: A Tiny Trick with Massive Impact

If get to know something new by reading my articles, don't forget to endorse me on LinkedIn
Unit Testing is a type of software testing where individual units or components of software are tested. The purpose is to validate that each unit of the software code performs as expected. Unit Testing is done during the development (coding phase) of an application by the developers. Unit Tests isolate a section of code and verify its correctness. A unit may be an individual function, method, procedure, module, or object.
Running tests on an Android emulator or device is slow! Building, deploying, and launching the app often takes a minute or more. That’s no way to do TDD. There must be a better way.
Robolectric is the industry-standard unit testing framework for Android. Robolectric is a framework that brings fast and reliable unit tests to Android. Tests run inside the JVM on your workstation in seconds.
Robolectric provides a JVM-compliant version of the android.jar file. Robolectric handles inflation of views, resource loading, and lots of other stuff that’s implemented in native C code on Android devices.
This enables you to run your Android tests in your continuous integration environment without any additional setup. Roboletric supports resource handling, e.g., inflation of views. You can also use the findViewById() to search in a view.
Roboletric is not an integration test framework, i.e., you cannot test the interaction of Android components with it.
Roboletric does not require additional mocking frameworks, of course, it is still possible to use frameworks like Mockito if desired.
Run tests in a simulated Android environment inside a JVM
Reduced overhead and flakiness of an emulator
Run 10x faster than those on cold-started emulators
Supports 17 different versions of Android
A testing tool for Android
Can test pure Java/Kotlin code
Provide the ability to test Android Framework code
Don't require a simulator to run the test
It uses the host machine to run the tests and which is much faster
Update your app build.gradle
android {
android {
testOptions {
unitTests {
includeAndroidResources = true
}
}
}
}
dependencies {
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.9'
}
Sync the project and Roboletric is ready for use

Let's create a class called RoboletricFirstTest under the test package.
@RunWith(RobolectricTestRunner::class)
class RoboletricFirstTest {
private var conditionToMatch = ""
@Before
fun setup() {
conditionToMatch = "Hello Roboletric!"
}
@Test
fun `our first test to match the greetings`() {
assert(conditionToMatch == "Hello Roboletric!")
}
@After
fun release() {
conditionToMatch = ""
}
}
Run the test (ctrl+shift+F10)and check the output:
✅ Tests passed: 1 out 1 test
Congratulations, we successfully passed our first Roboletric Test.
Things to notice:
testImplementation 'org.robolectric:robolectric:4.9' test implementation is applicable for test package only but not for androidTest package. For androidTest package use androidTestImplementation.
Test classes must be annotated with @RunWith(RobolectricTestRunner::class)
In a class, there might be several tests and to run those tests, we may need to initialize some dependent objects before the test runs. To initialize objects use the annotation @Before in your method.
And to release the object when the tests are finished, use the annotation @After in your method.
Let's think about practical testing where we might want to test our repository, repository is responsible for making a network call and returning the response. [But for testing purposes, we are using a mock repository implementation]

Create a new repository(interface) under a package called com.rommansabbir.robolectricexample.basictesting
interface AuthRepository {
fun login(username : String, password : String): String
fun register(username: String, password: String): Boolean
}
Our auth repository contains two APIs called login and register. In a real project, we will have the implementation of network calls.

Create two new classes called AuthRepositoryTestImpl and AuthRepositoryTest under the package called com. rommansabbir.roboletricexample.basictesting(test package).
class AuthRepositoryTestImpl : AuthRepository {
override fun login(username: String, password: String): String {
//make network request here
return if (username == "rommansabbir" && password == "123456") "login_access" else "Login error"
}
override fun register(username: String, password: String): Boolean {
//make network request here
return username == "rommansabbir" && password == "123456"
}
}
Here is our test implementation of auth repository.
@RunWith(RobolectricTestRunner::class)
class AuthRepositoryTest {
private var authRepo: AuthRepository? = null
@Before
fun setup() {
authRepo = AuthRepositoryTestImpl()
}
@Test
fun `test a valid login`() {
assert(authRepo?.login("rommansabbir", "123456") == "login_access")
}
@Test
fun `test a invalid login`() {
assert(authRepo?.login("rommansabbir", "password") == "Login error")
}
@Test
fun `test a valid registration`() {
assert(authRepo?.register("rommansabbir", "123456") == true)
}
@Test
fun `test a invalid registration`() {
assert(authRepo?.register("rommansabbir", "password") == false)
}
@After
fun release() {
authRepo = null
}
}
Here are our tests for auth repository.
Run the test (ctrl+shift+F10)and check the output:
✅ Tests passed: 4 out 4 test

In our test, we might need to use the application context to run tests (ex: SharedPreferences usages). Let's create a new class called AppContextTest.
@RunWith(RobolectricTestRunner::class)
class AppContextTest {
private var context: Application? = null
private var sharedPreferences: SharedPreferences? = null
private val key: String = "TEST_KEY"
@Before
fun setup() {
context = ApplicationProvider.getApplicationContext()
sharedPreferences = context?.getSharedPreferences("test", Context.MODE_PRIVATE)
}
@Test
fun `context and shared pref should be not null`() {
assert(context != null)
assert(sharedPreferences != null)
}
@Test
fun `test a shared pref writing & get the written object`() {
var writeDone = false
sharedPreferences?.edit {
putBoolean(key, true)
commit()
writeDone = true
}
assert(writeDone)
assert(sharedPreferences?.getBoolean(key, false) == writeDone)
}
@After
fun release() {
sharedPreferences = null
context = null
}
}
Here, we are getting the application context by accessing the ApplicationProvider.getApplicationContext() API. We need to add the required dependency testImplementation 'androidx.test:core:1.5.0'
Run the test (ctrl+shift+F10)and check the output:
✅ Tests passed: 2 out 2 test
Let's test a Activity, where we will test the button name maches to a string (resource) and button click is performed.
@RunWith(RobolectricTestRunner::class)
class MainActivityTest {
private var mainActivity: MainActivity? = null
@Before
fun setup() {
mainActivity = Robolectric.buildActivity(MainActivity::class.java).create().resume().get()
}
@Test
fun `check activity is initialized properly`() {
assert(mainActivity != null)
}
@Test
fun `check the button name`() {
assert(mainActivity?.binding?.mainButton?.text == mainActivity?.getString(R.string.welcome_button))
}
@Test
fun `check button pressed`() {
var isPressed = false
mainActivity?.binding?.mainButton?.apply {
setOnClickListener{
isPressed = true
}
performClick()
}
assert(isPressed)
}
@Test
fun release() {
mainActivity = null
}
}
Run the test (ctrl+shift+F10)and check the output:
✅ Tests passed: 4 out 4 test

Create a new service called MyService under package com.rommansabbir.robolectricexample.myservice
class MyService : Service() {
companion object {
var isServiceInitialized = false
var isServiceDestroyed = false
}
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
isServiceInitialized = true
}
override fun onDestroy() {
super.onDestroy()
isServiceDestroyed = true
}
}
Create a class called MyServiceTest under package com.rommansabbir.robolectricexample.myservice (test package)
@RunWith(RobolectricTestRunner::class)
class MyServiceTest {
private var service: MyService? = null
@Before
fun setup() {
service = Robolectric.buildService(MyService::class.java).get()
MyService.isServiceInitialized = false
MyService.isServiceDestroyed = false
}
@Test
fun `check if the service is created by calling onCreate method`() {
service?.onCreate()
assert(MyService.isServiceInitialized)
}
@Test
fun `check if the service is destroyed by calling onDestroy method`() {
service?.onDestroy()
assert(MyService.isServiceDestroyed)
}
@After
fun release() {
service = null
}
}
Run the test (ctrl+shift+F10)and check the output:
✅ Tests passed: 2 out 2 test
If get to know something new by reading my articles, don't forget to endorse me on LinkedIn
I hope this article will help you to cover basic Android testing with Roboletric.
Project Link (Github): Click here to view the repository
That's it for today. Happy Coding...