Build local unit tests

You can evaluate your app's logic using local unit tests when you need to run tests more quickly and don't need the fidelity and confidence associated with running tests on a real device. With this approach, you normally fulfill your dependency relationships using either Robolectric or a mocking framework, such as Mockito. Usually, the types of dependencies associated with your tests determine which tool you use:

  • If you have dependencies on the Android framework, particularly those that create complex interactions with the framework, it's better to include framework dependencies using Robolectric.
  • If your tests have minimal dependencies on the Android framework, or if the tests depend only on your own objects, it's fine to include mock dependencies using a mocking framework like Mockito.

Set up your testing environment

In your Android Studio project, you must store the source files for local unit tests at module-name/src/test/java/. This directory already exists when you create a new project.

You also need to configure the testing dependencies for your project to use the standard APIs provided by the JUnit 4 framework. If your test needs to interact with Android dependencies, include Robolectric or the Mockito library to simplify your local unit tests.

In your app's top-level build.gradle file, specify the following libraries as dependencies:

dependencies {
    // Required -- JUnit 4 framework
    testImplementation 'junit:junit:4.12'
    // Optional -- Robolectric environment
    testImplementation 'androidx.test:core:1.0.0'
    // Optional -- Mockito framework
    testImplementation 'org.mockito:mockito-core:1.10.19'
}

Create a local unit test class

Your local unit test class should be written as a JUnit 4 test class. JUnit is the most popular and widely-used unit testing framework for Java. JUnit 4 allows you to write tests in a cleaner and more flexible way than its predecessor versions because JUnit 4 doesn't require you to do the following:

  • Extend the junit.framework.TestCase class.
  • Prefix your test method name with the 'test' keyword.
  • Use classes from the junit.framework or junit.extensions packages.

To create a basic JUnit 4 test class, create a class that contains one or more test methods. A test method begins with the @Test annotation and contains the code to exercise and verify a single functionality in the component that you want to test.

The following example shows how you might implement a local unit test class. The test method emailValidator_CorrectEmailSimple_ReturnsTrue verifies that the isValidEmail() method in the app under test returns the correct result.

Kotlin

import com.google.common.truth.Truth.assertThat
import org.junit.Test

class EmailValidatorTest {
    @Test
    fun emailValidator_CorrectEmailSimple_ReturnsTrue() {
        assertThat(EmailValidator.isValidEmail("name@email.com")).isTrue()
    }
}

Java

import com.google.common.truth.Truth.assertThat;
import org.junit.Test;

public class EmailValidatorTest {
    @Test
    public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
        assertThat(EmailValidator.isValidEmail("name@email.com")).isTrue();
    }
}

To create readable tests that evaluate whether the components in your app return the expected results, we recommend using the Truth library and classes from Android Assertions, as shown in the preceding example. To learn more about the types of logic validation that Truth and Android Assertions support, see the section describing how to create more readable assertions.

If you're more comfortable comparing expected and actual results using junit.Assert methods or Hamcrest matchers (such as the is() and equalTo() methods), however, it's OK to use those libraries instead.

Note: Hamcrest is still the preferred library to use when constructing matchers, such as for Espresso's ViewMatcher class.

Include framework dependencies

If your tests interact with several Android framework dependencies, or interact with those dependencies in a complex way, use the Robolectric artifacts that AndroidX Test provides. Robolectric executes real Android framework code and fakes of native framework code on your local JVM or on a real device.

The following example shows how you might create a unit test that uses Robolectric:

app/build.gradle

android {
    // ...
    testOptions {
        unitTests.includeAndroidResources = true
    }
}

MyLocalUnitTestClass

Kotlin

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import com.google.common.truth.Truth.assertThat
import org.junit.Test

private const val FAKE_STRING = "HELLO_WORLD"

class UnitTestSample {
    val context = ApplicationProvider.getApplicationContext<Context>()

    @Test fun readStringFromContext_LocalizedString() {
        // Given a Context object retrieved from Robolectric...
        val myObjectUnderTest = ClassUnderTest(context)

        // ...when the string is returned from the object under test...
        val result: String = myObjectUnderTest.getHelloWorldString()

        // ...then the result should be the expected one.
        assertThat(result).isEqualTo(FAKE_STRING)
    }
}

Java

import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Test;

import static com.google.common.truth.Truth.assertThat;

public class UnitTestSampleJava {
    private static final String FAKE_STRING = "HELLO_WORLD";
    private Context context = ApplicationProvider.getApplicationContext();

    @Test
    public void readStringFromContext_LocalizedString() {
        // Given a Context object retrieved from Robolectric...
        ClassUnderTest myObjectUnderTest = new ClassUnderTest(context);

        // ...when the string is returned from the object under test...
        String result = myObjectUnderTest.getHelloWorldString();

        // ...then the result should be the expected one.
        assertThat(result).isEqualTo(FAKE_STRING);
    }
}

Include Android Builder classes

If you're creating local unit tests that you run in a Robolectric environment or on a real device, you can use the builders that AndroidX Test provides for several common framework classes. These builders allow you to create instances of the following classes without needing to use mocks or reflection:

Use Parcelables utility class

In addition, the library provides a utility class for Parcelable objects. By providing a Creator object, this class unmarshals the given Parcelable object, and then marshals a duplicate Parcelable object.

Note: It's up to the method that calls Parcelables.forceParcel() to verify that the unmarshal/remarshal operation has succeeded.

Include mock dependencies

By default, the Android Plug-in for Gradle executes your local unit tests against a modified version of the android.jar library, which does not contain any actual code. Instead, method calls to Android classes from your unit test throw an exception. This is to make sure you test only your code and do not depend on any particular behavior of the Android platform (that you have not explicitly built or mocked).

Mock Android dependencies

If you have minimal Android dependencies and need to test specific interactions between a component and its dependency within your app, use a mocking framework to stub out external dependencies in your code. That way, you can easily test that your component interacts with the dependency in an expected way. By substituting Android dependencies with mock objects, you can isolate your unit test from the rest of the Android system while verifying that the correct methods in those dependencies are called. The Mockito mocking framework for Java (version 1.9.5 and higher) offers compatibility with Android unit testing. With Mockito, you can configure mock objects to return some specific value when invoked.

To add a mock object to your local unit test using this framework, follow this programming model:

  1. Include the Mockito library dependency in your build.gradle file, as described in Set up your testing environment.
  2. At the beginning of your unit test class definition, add the @RunWith(MockitoJUnitRunner.class) annotation. This annotation tells the Mockito test runner to validate that your usage of the framework is correct and simplifies the initialization of your mock objects.
  3. To create a mock object for an Android dependency, add the @Mock annotation before the field declaration.
  4. To stub the behavior of the dependency, you can specify a condition and return value when the condition is met by using the when() and thenReturn() methods.

The following example shows how you might create a unit test that uses a mock Context object.

Kotlin

import android.content.Context
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnitRunner

private const val FAKE_STRING = "HELLO WORLD"

@RunWith(MockitoJUnitRunner::class)
class UnitTestSample {

    @Mock
    private lateinit var mockContext: Context

    @Test
    fun readStringFromContext_LocalizedString() {
        // Given a mocked Context injected into the object under test...
        `when`(mockContext.getString(R.string.hello_word))
                .thenReturn(FAKE_STRING)
        val myObjectUnderTest = ClassUnderTest(mockContext)

        // ...when the string is returned from the object under test...
        val result: String = myObjectUnderTest.getHelloWorldString()

        // ...then the result should be the expected one.
        assertThat(result, `is`(FAKE_STRING))
    }
}

Java

import android.content.Context;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class UnitTestSample {

    private static final String FAKE_STRING = "HELLO WORLD";

    @Mock
    Context mMockContext;

    @Test
    public void readStringFromContext_LocalizedString() {
        // Given a mocked Context injected into the object under test...
        when(mMockContext.getString(R.string.hello_world))
                .thenReturn(FAKE_STRING);
        ClassUnderTest myObjectUnderTest = new ClassUnderTest(mMockContext);

        // ...when the string is returned from the object under test...
        String result = myObjectUnderTest.getHelloWorldString();

        // ...then the result should be the expected one.
        assertThat(result, is(FAKE_STRING));
    }
}

To learn more about using the Mockito framework, see the Mockito API reference and the SharedPreferencesHelperTest class in the sample code. Also try the Android Testing Codelab.

Error: "Method ... not mocked"

If you run a test that calls an API from the Android SDK that you do not mock, you'll receive an error that says this method is not mocked. That's because the android.jar file used to run unit tests does not contain any actual code (those APIs are provided only by the Android system image on a device).

Instead, all methods throw exceptions by default. This is to make sure your unit tests only test your code and don't depend on any particular behavior of the Android platform (that you have not explicitly mocked, such as with Mockito).

If the exceptions thrown are problematic for your tests, you can change the behavior so that methods instead return either null or zero by adding the following configuration in your project's top-level build.gradle file:

android {
  ...
  testOptions {
    unitTests.returnDefaultValues = true
  }
}

Caution: Setting the returnDefaultValues property to true should be done with care. The null/zero return values can introduce regressions in your tests, which are hard to debug and might allow failing tests to pass. Only use it as a last resort.

Run local unit tests

To run your local unit tests, follow these steps:

  1. Be sure your project is synchronized with Gradle by clicking Sync Project in the toolbar.
  2. Run your test in one of the following ways:
    • To run a single test, open the Project window, and then right-click a test and click Run .
    • To test all methods in a class, right-click a class or method in the test file and click Run .
    • To run all tests in a directory, right-click on the directory and select Run tests .

The Android Plugin for Gradle compiles the local unit test code located in the default directory (src/test/java/), builds a test app, and executes it locally using the default test runner class. Android Studio then displays the results in the Run window.