Beginning Android Test Driven Development with Robolectric

Shares
Android Unit Testing

One of my new year resolution for 2016 is to master Android Test driven development(TDD). This is easier said than done because  it is not easy to implement or follow TDD in Android. One of the reasons TDD and testing in general is challenging in Android is mock or the lack thereof!. And who are we mocking here you may ask?

To understand the need for mock, you will need to remember that the things that make an Android app rock comes alive on the device. So if you want to test a given functionality or feature of your app, you have to run the app on the device to verify that the app produces the expected result. If you want to automate this process, that is if you do not want to manually run the app in the device in other to test it, then you will need to mimic the Android components that comes alive on the device such as Activity, Intent, Service etc.

The fake component that you create to mimic the real Android component is called a “Mock” or “Shadow” in Robolectric as you will see later in the tutorial. Mocks are just one tool you will need in your Android testing tool kit, there are other tools, terms and concepts you will need get familiarize with if you want to introduce testing in your Android development workflow. I will point some of them out in the course of this post.

What is Test Driven Development? TDD is a software development approach whereby you write a test that describes an expected feature of your app before that feature is implemented. At first the test will fail, then after you implement the feature, the test will now pass. At this point you can refactor your app to behave in a meaningful way but still pass the test. It may be tempting to think that TDD is some kind of trial and error approach of development, while in reality you need to have a clear understanding of what you are building before you can write a meaningful test.

And just incase you are wondering what is Unit Testing  –  with unit testing, we test our app one event at a time as you will see in this tutorial. For example instead of testing whether the click of a button resulted in the creation of a Guest object, we can do a unit testing that checks if the click of the button fired an event in the first place. We can then do another unit test that checks for example if the correct Intent was started or if the correct event was posted to the event bus.

Sample Project

Demo Android Unit Testing

Demo Android Unit Testing

The sample project for this post is a Guest List App. This simple app, shows a list of guests. When you click on a guest you will be taken to a screen where you  can check the guest in or check the guest out. There is a floating action button that when clicked will take you to another screen where you can  add a guest. We will implement just enough of this app functionality to provide an adequate introduction to Android Test Driven Development with Robolectric.

 

Step 1 - Project Creation

  1. Create a new Android Studio project and select the defaults (API level 16, Blank Activity, Main Activity).
  2. For this post I am using Gradle 1.5.0 and build tools 23.0.2 so you may want to update your Android Studio if you want to follow along.
  3. Next you want to set your Test Artifact to Unit Test so that our Unit Tests will be included in the build.
    Android Studio Build Variant

    Android Studio Build Variant

  4. Ensure that Android Studio created a test directory for you as show below. If not you will need to open your project in project view and add a test folder.test_directory

Step 2 - Add Dependencies

All we had to do to start writing our unit tests is to pull in the dependency for Robolectric, testing is now fully supported in Android Studio. I recently read an excellent book on Android Test Driven development where whole two chapters was dedicated to setting up Robolectric testing in Android Studio, that is no longer the case. If you are getting started with Android development I highly recommend that book  which is titled Android Activity (its in Beta) by @corey_latislaw

Add the following dependencies to your build.gradle file and rebuild, the one that had (Module: app) next to it. We will use the other libraries as we continue in this tutorial.

Source Code

The source code for this demo app is available, please show your support by sharing this post through any of your social media channel to get access to the source code.

[Locker] The locker [id=1996] doesn't exist or the default lockers were deleted.
https://github.com/valokafor/GuestListApp[/sociallocker]

Step 3 - Write Your First Unit Test

According to the test driven development purists – thou shall not write a line of code unless you have first written a failing test. The question then is what do we test? And in what order?.  The reality again is that you need a good understanding of the app you are building in other to determine what to test and in what order. This all comes with practice and in some cases you simply have to violate the commandment of test first development approach due to certain constraints that are unique to Android development.

It is best practice to greatly limit the code/logic we want to put in our Activity. Because of this, we will create a Fragment that will take on the responsibility of our Main Activity, we will call this Fragment AppStateFragment. Since we have not created this Fragment yet, it is therefore a good candidate for our first unit test. Since this Fragment is crucial to the app, we should write a unit test that verifies that it exists.

  1. In your test package add the Java class file called AppStateFragmentTest.java,
  2. It is a good practice to name your test class files after the name of the production class files that they are testing.
  3. Annotate your test class with Robolectric Gradle test runner which allows this code to be run natively in the Java Virtual Machine instead of the Android device.
  4. Setup – your test class does not have artificial intelligence so we have to do some initialization for any test class that we create. Right click anywhere in your class, select Generate>Setup Method to add a setup method like this.
  5. At the top of your test class declare a class member private AppStateFragment fragment  , the IDE will give you a warning that this file does not exist and offer to create, go ahead and create that Fragment by yourself at the root of your project or create another package called fragments.
  6. Now right click again in your test class and select Generate>Test Method and name that test method shouldNotBeNull like below. You will receive a req squiggly error on “assertNotNull” right click and do static import of  import static junit.framework.TestCase.assertNotNull;
  7. Run the test by right clicking the method and selecting run and  the test will fail, . Great! We ran a unit test. To make the test pass, create the fragment in the setup method. Run the test again after you instantiate the Fragment and the test should pass.
  8. Now that our test has passed , we need to actually refactor our production code to implement the behavior that we are testing, this process if often referred to as Red, Green and Refactor. Add this factory method to the AppStateFragment.java class that returns an instance of the Fragment.
    And this code to the MainActivity and call the method in your onCreate() method. Add the constant  public static final String STATE_FRAGMENT_TAG = "GuestListState";  at the top of your MainActivity class.
     

Step 4 - Create Guest List Fragment

  1. Add a Fragment named GuestListFragment.java to your fragments package and it should have a corresponding layout file named fragment_guest_list.xml
  2. Also add GuestListFragmentTest.java to your test package. Add  the Robolectric Test runner annotation like we did before and also add a setup method and a class member private GuestListFragment fagment  to that class
  3. Add a factory method that creates and returns GuestListFragment.java like this
  4. Then in the AppStateFragment.java, update the oncreate method to create this Fragment like so
  5. At this point, you can add a shouldNotBeNull test to the GuestListFragmentTest.java like we did before and it should pass

Step 5 - Update Layout

  1. Move the floating action button that the Android new project wizard added to activity_main.xml to the fragment_guest_list.java. Also add a listview to the GustListFragment layout file and this layout file will now look like this.
  2. The MainActivity layout file will now look like this (add an id of container to the content_main)
     

Step 6 - Add Unit Tests for ListView

We are using a listview to display the list of guests. We need to add a unit test that verifies that the listview is visible. And even if the listview is visible, it does us no good if that listview does not have an adapter associated with it so we also have to check if it has an adapter.

  1. Add a test method to your GuestListFragmentTest.java with the name guestListShouldNotBeNull() like this (add static import for the Robolectic method “startFragment”
  2. You should receive a red squiggly line that the IDE does not recognize assertViewIsVisible() test method, that it because it is a helper method that I added.
  3. Create a class called TestHelper.java in your test package and add the method like so
  4. Run the test and it should fail because the listview is not visible and the listview does not have an adapter yet.

Step 7 - Implement Adapter

  1. To implement adapter add two packages to the root of your project: adapters and models
  2. In the models package add a class file name Guest.java with the following content – use Android Studio to generate getters and setters
  3. In the adapters package add the class file GuestListAdapter.java with following content
  4. Add the  <uses-permission android:name="android.permission.INTERNET" /> for Picasso and also add any image a place holder for Picasso and give it the name profile_icon.jpg
  5. Add layout file for out listview named guest_list_custom_row.xml with the following content
  6. With this we can now setup the listview in GuestListFragment.java like this
  7. Run the failing test again in GuestListFragmentTest.java and it should pass.

Step 8 - Populate ListView

Even though our test is passing, we still have a blank list so let us populate our list with some guests. First let us write a unit test that checks that our list have more than zero guest.

Add a test method named listViewShouldNotBeEmpty() to GuestListFragmentTest.java with the content below. Note that before we have to create a Shadow of our listview using Robolectric, and then we have to call the populateItems() method on this Shadow listview before we can get item count out of it.

As expected, if run this test now, it will fail because our list is still empty. Go ahead and run the test listViewShouldNotBeEmpty(). You may get the error message “cannot access AndroidHttpClient”, if you do per this StackOverflow  answer add  useLibrary 'org.apache.http.legacy'  to your gradle and the test should now run and fail.

cannot access AndroidHttpClient

cannot access AndroidHttpClient

 

To add some demo data:

  1. Add a package named data to the root of you app.
  2. Add a class named SampleData.java
  3. In this class add a method named getSampleData() with the following content:
  4. Then update the initializeView() method in GuestListFragment.java to now call this method like so:
  5. Run the failing tests and it should now pass because we have more than zero items in the list

 

Summary

We have not come to the end of part 1 of this beginning Android Test Driven Development with Robolectric. In the next post we will add unit tests for the key functionality of the app which is check in and check out of guest. We will use Otto event bus to create events that we can now write the tests against. If you have not already subscribed to my email list please do so.

Leave me a comment to let know if you find the post useful or if you are struggling with a particular concept. We have barely scratched the surface of unit testing here and that is just one half of Android testing. I will write a future post once I wrap my head fully around the other side of Android testing which is integration testing or UI testing using Espresso.

For now, keep coding – code answereth all things!

About the Author valokafor

I am a Software Engineer with expertise in Android Development. I am available for Android development projects.

follow me on:

Leave a Comment: