Introduction to Automated Android Testing – Part 6

Introduction to Automated Android Testing – Part 6

In the previous 5 blog posts, we covered different aspects of building an Android app from scratch. We focused on including tests in the process. Here are the links to the previous posts:

  • Post #1 – Why should we write tests?
  • Post #2 – Set up your app for testing
  • Post #3 – Creating API calls
  • Post #4 – Creating repositories
  • Post #5 – Following the MVP pattern

In this last post of the series, we will cover creating Espresso tests for the View we created in part 5. The Github repo for this post can be found here.

Testing that a view contains the exact information expected can be tricky if the data is dynamic. This data can change at any time and our tests should not fail because of it. In order for the tests to be reliable and repeatable, we should not call any production APIs.

Mocking out the responses of the API calls will enable us to write tests that depend on the mocked data. There are a couple of ways in which we can mock out our API calls:

  • Option 1 – Use WireMock and run a standalone server which serves up the same static JSON for specific network calls.
  • Option 2 – Use OkHttp’s MockWebServer which runs a webserver on your device and serves up any response you request.
  • Option 3 – Create a custom implementation of the Retrofit REST interface that returns dummy objects.

Obviously, the choice is entirely up to you as to how you would want to go about writing UI tests. In my case, WireMock is extra effort as I would need to ensure I have a standalone server running with a static IP address.

MockWebServer is a lot easier to use than WireMock as you don’t have to set up a standalone web server (The server runs on the device). MockWebServer is also flexible because you can give it different scenarios. Useful features like specifying the failure rate of a certain call or simulating a slow network are possible using MockWebServer. (Read more here).

I am going to use option 3 for the purpose of testing that the UI matches the mock response data. If I wanted to add tests for slow network conditions (or some kind of non-functional test), I would choose option 2. If you are unable to use OkHttp,  I would choose option 1 as Wiremock works with any HTTP client.

Mocking out data using Gradle flavors

By making use of Gradle flavors, we can easily mock out of API responses.  If you read post #2 on Gradle flavors, you should already have a “mock” and a “production” flavor set up.

  1. Make sure you are switched to the mockDebug flavor. Select mockDebug variant
  2. Create a mock folder in the src directory. Then create a package within the mock folder, that mimics the main package name. Make a class called MockGithubUserRestServiceImpl. Your resulting file structure should look like this: Folder structure for mock testing
  3. Create a prod directory. Move the Injection class defined previously into this folder. We will be creating another Injection class in the mock folder. This class will inject the mocked out Github service instead of the production API. Move Injection to prod and create one in mock folderIn the Injection class that is located in the mock folder, we simply return the MockGithubUserServiceImpl that we created. In the prod folder, we return the actual Retrofit Github service. 
    Mock Injection class:

    Prod Injection class:
  4. The data returned from the mock service is dependant on your specific requirements. Below is my implementation of the MockGithubUserRestServiceImpl:

    In this case, I am just returning some dummy data. Let’s run the mock version of the app and we should get the same results no matter what you search.

    Android Test app with mock data

    Cool. Now we have a working dummy app! We can now write Espresso UI tests. 

Basics of Writing an Espresso Test

When writing an Espresso test, the following formula is used for performing functions within your UI:

  • ViewMatchers – Used to find a view in an activity. There are a bunch of different kinds of matchers. For example: withId(R.id.menu_search), withText("Search"), withTag("custom_tag") .
  • ViewActions – Used to interact with a view. For example: click(), doubleClick(), swipeUp(), typeText().
  • ViewAssertations – Used to make assertions that certain views possess specific properties. For example:   doesNotExist(), isAbove(), isBelow().

There is a great cheat sheet for the different Espresso methods that can be found in pdf form here: android-espresso-testing.pdf. It is worth mentioning that ordinary hamcrest matchers can be used when writing Espresso tests. Methods such as not(), allOf()  and anyOf() are valid.

Writing Espresso UI Tests

If you can recall, in post #2 we covered what dependencies will need to be added in order to write espresso tests. Now we will cover writing an Espresso test.

  1. Create a folder androidTestMock. The tests in this folder will only run on the mock variant and not on the production variant. Then make a directory that matches the main package name. In that directory, add a new class called  UserSearchActivityTest. Your project should then look like this:androidTestMock folder
  2. We will start by writing a basic test that ensures that when the activity is started, the text “Start typing to search” is displayed:

    The @Rule  ActivityTestRule specifies which activity this test will run with. In this case this test will run with UserSearchActivity. This will automatically start up the UserSearchActivity. Passing extra parameters will indicate if you want the activity to auto start or not.

    The test searchActivity_onLaunch_HintTextDisplayed() is quite simple. It searches in the view for the text and asserts that the text is visible on the UI.

  3. The next test is slightly more complicated:

    After typing into the SearchView and pressing enter, we assert that the dummy results are displayed on the UI.

  4. We have now written tests for the positive scenarios, we should add a test for the negative case too. We will need to adjust the MockGithubUserRestServiceImpl in order to allow it to return custom error observables if required.

    In the code above, a method was created in order to set a dummy observable for the search results. That observable will be returned if it is not null when searchGithubUsers() is called.

  5. Now we can create a test that checks if the error is displayed on the UI.

    In this test, we first ensure that the service will return an exception. Then we assert that the error message is displayed on the UI.

  6. Let’s run the tests:

Passing_UI_Tests

They all pass!

Code Coverage in Android

In order to know how effective your tests are, it is great to get code coverage metrics.

  1. To enable code coverage on your UI tests, add testCoverageEnabled = true  to your build.gradle:
  2. Run the task createMockDebugCoverageReport. You will then find the HTML report located here: app/build/reports/coverage/mock/debug/index.html.

Code Coverage Report in Android

Yay – we have 82% coverage just with the mock UI test. Taking into consideration the coverage reports we saw in post #4 and this post, it gives us a good indication of the test coverage of our entire app. Now we can iteratively go back and try cover more areas of our code.

PS – Code coverage currently doesn’t work with the Jack compiler. I switched to use Retrolambda in order to get the code coverage report to work. If you are interested in learning more, check out this branch.

Conclusion

We have finished writing our feature. Whew! 6 blog posts later. There is obviously a lot more testing that can be completed in this app. Non-functional tests such as testing how your app behaves on devices with low memory or with poor network connectivity can also be added.
That concludes the series on an “Introduction to Automated Android Testing”. I hope you enjoyed reading this series. If you enjoyed it, be sure to subscribe to the blog to receive future updates and share the post with your friends.

Further Reading

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.


If you would like to see more posts from me, please consider buying me a cupcake to keep them coming.

[buy_cupcake]


3 Replies to “Introduction to Automated Android Testing – Part 6”

  1. Ty for sharing this. But i think your series have stopped on the most interesting place, because it definitely lacks a guide about best practices of dagger 2 usage for android functional testing, doesn’t it? 🙂

Comments are closed.