• 18-19 College Green, Dublin 2
  • 01 685 9088
  • info@cunninghamwebsolutions.com
  • cunninghamwebsolutions
    Cunningham Web Solutions
    • Home
    • About Us
    • Our Services
      • Web Design
      • Digital Marketing
      • SEO Services
      • E-commerce Websites
      • Website Redevelopment
      • Social Media Services
    • Digital Marketing
      • Adwords
      • Social Media Services
      • Email Marketing
      • Display Advertising
      • Remarketing
    • Portfolio
    • FAQ’s
    • Blog
    • Contact Us
    MENU CLOSE back  

    How To Improve Test Coverage For Your Android App Using Mockito And Espresso

    You are here:
    1. Home
    2. Web Design
    3. How To Improve Test Coverage For Your Android App Using Mockito And Espresso
    Thumbnail for 21185

    How To Improve Test Coverage For Your Android App Using Mockito And Espresso

    How To Improve Test Coverage For Your Android App Using Mockito And Espresso

    Vivek Maskara

    2018-07-25T14:00:04+02:00
    2018-07-25T12:06:31+00:00

    In app development, a variety of use cases and interactions come up as one iterates the code. The app might need to fetch data from a server, interact with the device’s sensors, access local storage or render complex user interfaces.

    The important thing to consider while writing tests is the units of responsibility that emerge as you design the new feature. The unit test should cover all possible interactions with the unit, including standard interactions and exceptional scenarios.

    In this article, we will cover the fundamentals of testing and frameworks such as Mockito and Espresso, which developers can use to write unit tests. I will also briefly discuss how to write testable code. I’ll also explain how to get started with local and instrumented tests in Android.

    Recommended reading: How To Set Up An Automated Testing System Using Android Phones (A Case Study)

    Fundamentals Of Testing

    A typical unit test contains three phases.

  • First, the unit test initializes a small piece of an application it wants to test.
  • Then, it applies some stimulus to the system under test, usually by calling a method on it.
  • Finally, it observes the resulting behavior.
  • If the observed behavior is consistent with the expectations, the unit test passes; otherwise, it fails, indicating that there is a problem somewhere in the system under test. These three unit test phases are also known as arrange, act and assert, or simply AAA. The app should ideally include three categories of tests: small, medium and large.

    • Small tests comprise unit tests that mock every major component and run quickly in isolation.
    • Medium tests are integration tests that integrate several components and run on emulators or real devices.
    • Large tests are integration and UI tests that run by completing a UI workflow and ensure that the key end-user tasks work as expected.

    Note: An instrumentation test is a type of integration test. These are tests that run on an Android device or emulator. These tests have access to instrumentation information, such as the context of the app under test. Use this approach to run unit tests that have Android dependencies that mock objects cannot easily satisfy.

    Nope, we can’t do any magic tricks, but we have articles, books and webinars featuring techniques we all can use to improve our work. Smashing Members get a seasoned selection of magic front-end tricks — e.g. live designing sessions and perf audits, too. Just sayin’! 😉

    Explore Smashing Wizardry →

    Writing small tests allows you to address failures quickly, but it’s difficult to gain confidence that a passing test will allow your app to work. It’s important to have tests from all categories in the app, although the proportion of each category can vary from app to app. A good unit test should be easy to write, readable, reliable and fast.

    Here’s a brief introduction to Mockito and Espresso, which make testing Android apps easier.

    Mockito

    There are various mocking frameworks, but the most popular of them all is Mockito:

    Mockito is a mocking framework that tastes really good. It lets you write beautiful tests with a clean & simple API. Mockito doesn’t give you hangover because the tests are very readable and they produce clean verification errors.

    Its fluent API separates pre-test preparation from post-test validation. Should the test fail, Mockito makes it clear to see where our expectations differ from reality! The library has everything you need to write complete tests.

    Espresso

    Espresso helps you write concise, beautiful and reliable Android UI tests.

    The code snippet below shows an example of an Espresso test. We will take up the same example later in this tutorial when we talk in detail about instrumentation tests.

    @Test
    public void setUserName() {
        onView(withId(R.id.name_field)).perform(typeText("Vivek Maskara"));
        onView(withId(R.id.set_user_name)).perform(click());
        onView(withText("Hello Vivek Maskara!")).check(matches(isDisplayed()));
    }
    

    Espresso tests state expectations, interactions and assertions clearly, without the distraction of boilerplate content, custom infrastructure or messy implementation details getting in the way. Whenever your test invokes onView(), Espresso waits to perform the corresponding UI action or assertion until the synchronization conditions are met, meaning:

    • the message queue is empty,
    • no instances of AsyncTask are currently executing a task,
    • the idling resources are idle.

    These checks ensure that the test results are reliable.

    Writing Testable Code

    Unit testing Android apps is difficult and sometimes impossible. A good design, and only a good design, can make unit testing easier. Here are some of the concepts that are important for writing testable code.

    Avoid Mixing Object Graph Construction With Application Logic

    In a test, you want to instantiate the class under test and apply some stimulus to the class and assert that the expected behavior was observed. Make sure that the class under test doesn’t instantiate other objects and that those objects do not instantiate more objects and so on. In order to have a testable code base, your application should have two kinds of classes:

    • The factories, which are full of the “new” operators and which are responsible for building the object graph of your application;
    • The application logic classes, which are devoid of the “new” operator and which are responsible for doing the work.

    Constructors Should Not Do Any Work

    The most common operation you will do in tests is the instantiation of object graphs. So, make it easy on yourself, and make the constructors do no work other than assigning all of the dependencies into the fields. Doing work in the constructor not only will affect the direct tests of the class, but will also affect related tests that try to instantiate your class indirectly.

    Avoid Static Methods Wherever Possible

    The key to testing is the presence of places where you can divert the normal execution flow. Seams are needed so that you can isolate the unit of test. If you build an application with nothing but static methods, you will have a procedural application. How much a static method will hurt from a testing point of view depends on where it is in your application call graph. A leaf method such as Math.abs() is not a problem because the execution call graph ends there. But if you pick a method in a core of your application logic, then everything behind the method will become hard to test, because there is no way to insert test doubles

    Avoid Mixing Of Concerns

    A class should be responsible for dealing with just one entity. Inside a class, a method should be responsible for doing just one thing. For example, BusinessService should be responsible just for talking to a Business and not BusinessReceipts. Moreover, a method in BusinessService could be getBusinessProfile, but a method such as createAndGetBusinessProfile would not be ideal for testing. SOLID design principles must be followed for good design:

    • S: single-responsibility principle;
    • O: open-closed principle;
    • L: Liskov substitution principle;
    • I: interface segregation principle;
    • D: dependency inversion principle.

    In the next few sections, we will be using examples from a really simple application that I built for this tutorial. The app has an EditText that takes a user name as input and displays the name in a TextView upon the click of a button. Feel free to take the complete source code for the project from GitHub. Here’s a screenshot of the app:

    Testing example

    Large preview

    Writing Local Unit Tests

    Unit tests can be run locally on your development machine without a device or an emulator. This testing approach is efficient because it avoids the overhead of having to load the target app and unit test code onto a physical device or emulator every time your test is run. In addition to Mockito, you will also need to configure the testing dependencies for your project to use the standard APIs provided by the JUnit 4 framework.

    Setting Up The Development Environment

    Start by adding a dependency on JUnit4 in your project. The dependency is of the type testImplementation, which means that the dependencies are only required to compile the test source of the project.

    testImplementation 'junit:junit:4.12'
    

    We will also need the Mockito library to make interaction with Android dependencies easier.

    testImplementation "org.mockito:mockito-core:$MOCKITO_VERSION"

    Make sure to sync the project after adding the dependency. Android Studio should have created the folder structure for unit tests by default. If not, make sure the following directory structure exists:

    <Project Dir>/app/src/test/java/com/maskaravivek/testingExamples
    

    Creating Your First Unit Test

    Suppose you want to test the displayUserName function in the UserService. For the sake of simplicity, the function simply formats the input and returns it back. In a real-world application, it could make a network call to fetch the user profile and return the user’s name.

    @Singleton
    class UserService @Inject
    constructor(private var context: Context) {
        
        fun displayUserName(name: String): String {
            val userNameFormat = context.getString(R.string.display_user_name)
            return String.format(Locale.ENGLISH, userNameFormat, name)
        }
    }
    

    We will start by creating a UserServiceTest class in our test directory. The UserService class uses Context, which needs to be mocked for the purpose of testing. Mockito provides a @Mock notation for mocking objects, which can be used as follows:

    @Mock internal var context: Context? = null
    

    Similarly, you’ll need to mock all dependencies required to construct the instance of the UserService class. Before your test, you’ll need to initialize these mocks and inject them into the UserService class.

    • @InjectMock creates an instance of the class and injects the mocks that are marked with the annotations @Mock into it.
    • MockitoAnnotations.initMocks(this); initializes those fields annotated with Mockito annotations.

    Here’s how it can be done:

    class UserServiceTest {
        
        @Mock internal var context: Context? = null
        @InjectMocks internal var userService: UserService? = null
        
        @Before
        fun setup() {
            MockitoAnnotations.initMocks(this)
        }
    }
    

    Now you are done setting up your test class. Let’s add a test to this class that verifies the functionality of the displayUserName function. Here’s what the test looks like:

    @Test
    fun displayUserName() {
        doReturn("Hello %s!").`when`(context)!!.getString(any(Int::class.java))
        val displayUserName = userService!!.displayUserName("Test")
        assertEquals(displayUserName, "Hello Test!")
    }
    

    The test uses a doReturn().when() statement to provide a response when a context.getString() is invoked. For any input integer, it will return the same result, "Hello %s!". We could have been more specific by making it return this response only for a particular string resource ID, but for the sake of simplicity, we are returning the same response to any input.
    Finally, here’s what the test class looks like:

    class UserServiceTest {
        @Mock internal var context: Context? = null
        @InjectMocks internal var userService: UserService? = null
        @Before
        fun setup() {
            MockitoAnnotations.initMocks(this)
        }
         
        @Test
        fun displayUserName() {
            doReturn("Hello %s!").`when`(context)!!.getString(any(Int::class.java))
            val displayUserName = userService!!.displayUserName("Test")
            assertEquals(displayUserName, "Hello Test!")
        }
    }
    

    Running Your Unit Tests

    In order to run the unit tests, you need to make sure that Gradle is synchronized. In order to run a test, click on the green play icon in the IDE.

    making sure that Gradle is synchronized

    When the unit tests are run, successfully or otherwise, you should see this in the “Run” menu at the bottom of the screen:

    Large preview

    You are done with your first unit test!

    Writing Instrumentation Tests

    Instrumentation tests are most suited for checking values of UI components when an activity is run. For instance, in the example above, we want to make sure that the TextView shows the correct user name after the Button is clicked. They run on physical devices and emulators and can take advantage of the Android framework APIs and supporting APIs, such as the Android Testing Support Library.
    We’ll use Espresso to take actions on the main thread, such as button clicks and text changes.

    Setting Up The Development Environment

    Add a dependency on Espresso:

    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
    

    Instrumentation tests are created in an androidTest folder.

    <Project Dir>/app/src/androidTest/java/com/maskaravivek/testingExamples
    

    If you want to test a simple activity, create your test class in the same package as your activity.

    Creating Your First Instrumentation Test

    Let’s start by creating a simple activity that takes a name as input and, on the click of a button, displays the user name. The code for the activity above is quite simple:

    class MainActivity : AppCompatActivity() {
        
        var button: Button? = null
        var userNameField: EditText? = null
        var displayUserName: TextView? = null
        
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            AndroidInjection.inject(this)
            setContentView(R.layout.activity_main)
            initViews()
        }
        
        private fun initViews() {
            button = this.findViewById(R.id.set_user_name)
            userNameField = this.findViewById(R.id.name_field)
            displayUserName = this.findViewById(R.id.display_user_name)
        
            this.button!!.setOnClickListener({
                displayUserName!!.text = "Hello ${userNameField!!.text}!"
            })
        }
    }
    

    To create a test for the MainActivity, we will start by creating a MainActivityTest class under the androidTest directory. Add the AndroidJUnit4 annotation to the class to indicate that the tests in this class will use the default Android test runner class.

    @RunWith(AndroidJUnit4::class)
    class MainActivityTest {}
    

    Next, add an ActivityTestRule to the class. This rule provides functional testing of a single activity. For the duration of the test, you will be able to manipulate your activity directly using the reference obtained from getActivity().

    @Rule @JvmField var activityActivityTestRule = ActivityTestRule(MainActivity::class.java)
    

    Now that you are done setting up the test class, let’s add a test that verifies that the user name is displayed by clicking the “Set User Name” button.

    @Test
    fun setUserName() {
        onView(withId(R.id.name_field)).perform(typeText("Vivek Maskara"))
        onView(withId(R.id.set_user_name)).perform(click())
        onView(withText("Hello Vivek Maskara!")).check(matches(isDisplayed()))
    }
    

    The test above is quite simple to follow. It first simulates some text being typed in the EditText, performs the click action on the button, and then checks whether the correct text is displayed in the TextView.

    The final test class looks like this:

    @RunWith(AndroidJUnit4::class)
    class MainActivityTest {
        
        @Rule @JvmField var activityActivityTestRule = ActivityTestRule(MainActivity::class.java)
        
        @Test
        fun setUserName() {
            onView(withId(R.id.name_field)).perform(typeText("Vivek Maskara"))
            onView(withId(R.id.set_user_name)).perform(click())
            onView(withText("Hello Vivek Maskara!")).check(matches(isDisplayed()))
        }
    }
    

    Running Your Instrumentation Tests

    Just like for unit tests, click on the green play button in the IDE to run the test.

    clicking on the green play button in IDE to run the test

    Large preview

    Upon a click of the play button, the test version of the app will be installed on the emulator or device, and the test will run automatically on it.

    Large preview

    Intrumentation Testing Using Dagger, Mockito, And Espresso

    Espresso is one of the most popular UI testing frameworks, with good documentation and community support. Mockito ensures that objects perform the actions that are expected of them. Mockito also works well with dependency-injection libraries such as Dagger. Mocking the dependencies allows us to test a scenario in isolation.
    Until now, our MainActivity hasn’t used any dependency injection, and, as a result, we were able to write our UI test very easily. To make things a bit more interesting, let’s inject UserService in the MainActivity and use it to get the text to be displayed.

    class MainActivity : AppCompatActivity() {
        
        var button: Button? = null
        var userNameField: EditText? = null
        var displayUserName: TextView? = null
        
        @Inject lateinit var userService: UserService
        
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            AndroidInjection.inject(this)
            setContentView(R.layout.activity_main)
            initViews()
        }
        
        private fun initViews() {
            button = this.findViewById(R.id.set_user_name)
            userNameField = this.findViewById(R.id.name_field)
            displayUserName = this.findViewById(R.id.display_user_name)
        
            this.button!!.setOnClickListener({
                displayUserName!!.text = userService.displayUserName(userNameField!!.text.toString())
            })
        }
    }
    

    With Dagger in the picture, we will have to set up a few things before we write instrumentation tests.
    Imagine that the displayUserName function internally uses some API to fetch the details of the user. There should not be a situation in which a test does not pass due to a server fault. To avoid such a situation, we can use the dependency-injection framework Dagger and, for networking, Retrofit.

    Setting Up Dagger In The Application

    We will quickly set up the basic modules and components required for Dagger. If you are not
    familiar with Dagger, check out Google’s documentation on it. We will start adding dependencies for using Dagger in the build.gradle file.

    implementation "com.google.dagger:dagger-android:$DAGGER_VERSION"
    implementation "com.google.dagger:dagger-android-support:$DAGGER_VERSION"
    implementation "com.google.dagger:dagger:$DAGGER_VERSION"
    kapt "com.google.dagger:dagger-compiler:$DAGGER_VERSION"
    kapt "com.google.dagger:dagger-android-processor:$DAGGER_VERSION"
    

    Create a component in the Application class, and add the necessary modules that will be used in our project. We need to inject dependencies in the MainActivity of our app. We will add a @Module for injecting in the activity.

    @Module
    abstract class ActivityBuilder {
        @ContributesAndroidInjector
        internal abstract fun bindMainActivity(): MainActivity
    }
    

    The AppModule class will provide the various dependencies required by the application. For our example, it will just provide an instance of Context and UserService.

    @Module
    open class AppModule(val application: Application) {
        @Provides
        @Singleton
        internal open fun provideContext(): Context {
            return application
        }
        
        @Provides
        @Singleton
        internal open fun provideUserService(context: Context): UserService {
            return UserService(context)
        }
    }
    

    The AppComponent class lets you build the object graph for the application.

    @Singleton
    @Component(modules = [(AndroidSupportInjectionModule::class), (AppModule::class), (ActivityBuilder::class)])
    interface AppComponent {
        
        @Component.Builder
        interface Builder {
            fun appModule(appModule: AppModule): Builder
            fun build(): AppComponent
        }
        
        fun inject(application: ExamplesApplication)
    }
    

    Create a method that returns the already built component, and then inject this component into onCreate().

    open class ExamplesApplication : Application(), HasActivityInjector {
        @Inject lateinit var dispatchingActivityInjector: DispatchingAndroidInjector<Activity>
        
        override fun onCreate() {
            super.onCreate()
            initAppComponent().inject(this)
        }
        
        open fun initAppComponent(): AppComponent {
            return DaggerAppComponent
                .builder()
                .appModule(AppModule(this))
                .build()
        }
        
        override fun activityInjector(): DispatchingAndroidInjector<Activity>? {
            return dispatchingActivityInjector
        }
    }
    

    Setting Up Dagger In The Test Application

    In order to mock responses from the server, we need to create a new Application class that extends the class above.

    class TestExamplesApplication : ExamplesApplication() {
        
        override fun initAppComponent(): AppComponent {
            return DaggerAppComponent.builder()
                .appModule(MockApplicationModule(this))
                .build()
        }
        
        @Module
        private inner class MockApplicationModule internal constructor(application: Application) : AppModule(application) {
            override fun provideUserService(context: Context): UserService {
                val mock = Mockito.mock(UserService::class.java)
                `when`(mock!!.displayUserName("Test")).thenReturn("Hello Test!")
                return mock
            }
        }
    }
    

    As you can see in the example above, we’ve used Mockito to mock UserService and assume the results. We still need a new runner that will point to the new application class with the overwritten data.

    class MockTestRunner : AndroidJUnitRunner() {
        
        override fun onCreate(arguments: Bundle) {
            StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder().permitAll().build())
            super.onCreate(arguments)
        }
        
        @Throws(InstantiationException::class, IllegalAccessException::class, ClassNotFoundException::class)
        override fun newApplication(cl: ClassLoader, className: String, context: Context): Application {
            return super.newApplication(cl, TestExamplesApplication::class.java.name, context)
        }
    }
    

    Next, you need to update the build.gradle file to use the MockTestRunner.

    android {
        ...
        
        defaultConfig {
            ...
            testInstrumentationRunner ".MockTestRunner"
        }
    }
    

    Running The Test

    All tests with the new TestExamplesApplication and MockTestRunner should be added at androidTest package. This implementation makes the tests fully independent from the server and gives us the ability to manipulate responses.
    With the setup above in place, our test class won’t change at all. When the test is run, the app will use TestExamplesApplication instead of ExamplesApplication, and, thus, a mocked instance of UserService will be used.

    @RunWith(AndroidJUnit4::class)
    class MainActivityTest {
        @Rule @JvmField var activityActivityTestRule = ActivityTestRule(MainActivity::class.java)
        
        @Test
        fun setUserName() {
            onView(withId(R.id.name_field)).perform(typeText("Test"))
            onView(withId(R.id.set_user_name)).perform(click())
            onView(withText("Hello Test!")).check(matches(isDisplayed()))
        }
    }
    

    The test will run successfully when you click on the green play button in the IDE.

    successfully setting up Dagger and run tests using Espresso and Mockito

    Large preview

    That’s it! You have successfully set up Dagger and run tests using Espresso and Mockito.

    Conclusion

    We’ve highlighted that the most important aspect of improving code coverage is to write testable code. Frameworks such as Espresso and Mockito provide easy-to-use APIs that make writing tests for various scenarios easier. Tests should be run in isolation, and mocking the dependencies gives us an opportunity to ensure that objects perform the actions that are expected of them.

    A variety of Android testing tools are available, and, as the ecosystem matures, the process of setting up a testable environment and writing tests will become easier.

    Writing unit tests requires some discipline, concentration and extra effort. By creating and running unit tests against your code, you can easily verify that the logic of individual units is correct. Running unit tests after every build helps you to quickly catch and fix software regressions introduced by code changes to your app. Google’s testing blog discusses the advantages of unit testing.
    The complete source code for the examples used in this article is available on GitHub. Feel free to take a look at it.

    Smashing Editorial
    (da, lf, ra, al, il)

    From our sponsors: How To Improve Test Coverage For Your Android App Using Mockito And Espresso

    Posted on 25th July 2018Web Design
    FacebookshareTwittertweetGoogle+share

    Related posts

    Archived
    22nd March 2023
    Archived
    18th March 2023
    Archived
    20th January 2023
    Thumbnail for 25788
    Handling Continuous Integration And Delivery With GitHub Actions
    19th October 2020
    Thumbnail for 25778
    A Monthly Update With New Guides And Community Resources
    19th October 2020
    Thumbnail for 25781
    Supercharge Testing React Applications With Wallaby.js
    19th October 2020
    Latest News
    • Archived
      22nd March 2023
    • Archived
      18th March 2023
    • Archived
      20th January 2023
    • 20201019 ML Brief
      19th October 2020
    • Thumbnail for 25788
      Handling Continuous Integration And Delivery With GitHub Actions
      19th October 2020
    • Thumbnail for 25786
      The Future of CX with Larry Ellison
      19th October 2020
    News Categories
    • Digital Marketing
    • Web Design

    Our services

    Website Design
    Website Design

    A website is an important part of any business. Professional website development is an essential element of a successful online business.

    We provide website design services for every type of website imaginable. We supply brochure websites, E-commerce websites, bespoke website design, custom website development and a range of website applications. We love developing websites, come and talk to us about your project and we will tailor make a solution to match your requirements.

    You can contact us by phone, email or send us a request through our online form and we can give you a call back.

    More Information

    Digital Marketing
    Digital Marketing

    Our digital marketeers have years of experience in developing and excuting digital marketing strategies. We can help you promote your business online with the most effective methods to achieve the greatest return for your marketing budget. We offer a full service with includes the following:

    1. Social Media Marketing

    2. Email & Newsletter Advertising

    3. PPC - Pay Per Click

    4. A range of other methods are available

    More Information

    SEO
    SEO Services

    SEO is an essential part of owning an online property. The higher up the search engines that your website appears, the more visitors you will have and therefore the greater the potential for more business and increased profits.

    We offer a range of SEO services and packages. Our packages are very popular due to the expanse of on-page and off-page SEO services that they cover. Contact us to discuss your website and the SEO services that would best suit to increase your websites ranking.

    More Information

    E-commerce
    E-commerce Websites

    E-commerce is a rapidly growing area with sales online increasing year on year. A professional E-commerce store online is essential to increase sales and is a reflection of your business to potential customers. We provide professional E-commerce websites custom built to meet our clients requirements.

    Starting to sell online can be a daunting task and we are here to make that journey as smooth as possible. When you work with Cunningham Web Solutions on your E-commerce website, you will benefit from the experience of our team and every detail from the website design to stock management is carefully planned and designed with you in mind.

    More Information

    Social Media Services
    Social Media Services

    Social Media is becoming an increasingly effective method of marketing online. The opportunities that social media marketing can offer are endless and when managed correctly can bring great benefits to every business.

    Social Media Marketing is a low cost form of advertising that continues to bring a very good ROI for our clients. In conjuction with excellent website development and SEO, social media marketing should be an essential part of every digital marketing strategy.

    We offer Social Media Management packages and we also offer Social Media Training to individuals and to companies. Contact us to find out more.

    More Information

    Cunningham Web Solutions
    © Copyright 2025 | Cunningham Web Solutions
    • Home
    • Our Services
    • FAQ's
    • Account Services
    • Privacy Policy
    • Contact Us