Categories
android testing

Introduction to Automated Android Testing – Part 2 – Setup

In this series of posts we are going to look at an Introduction to Automated Android Testing. In Part 1 of this automated testing series, we covered why you should write tests, where the test folders are located and the different types of tests you get in Android.

In this post, we are going to go over the typical structure and setup of your Android app in order to enable testing. I will be creating a simple app from scratch in this series and walk through each step of my thought process. The app we will be creating is a simple app that searches the Github API for users. Below is a rough mockup of what we will be creating:

Android Automated Testing Sample App

We will be starting from scratch. If you follow the steps below, you should end up with the repository that looks like this.

Getting started with a new app

  1. Open up Android Studio, select “Start a new Android Project”.
  2. Call the project “Gus” (Github User Search – original I know 😂) and company domain “riggaroo.co.za” . This will create a package name – za.co.riggaroo.gus . Click next.Step1 Automated Android Test Project
  3. Next choose the versions of Android you wish to support (I generally don’t go lower than API 16. You will cover 95.2% of users if you choose API 16 and above). Select API version 16 and click “Next”. Step 2 Automated Android Test Project
  4. Select “Empty Activity” and click “Next”.Step 3 Automated Test Project Android
  5. Change the name of the activity to UserSearchActivity  and the layout file to activity_user_search. Click “Finish”.Step 4 Naming default user activity.
  6. If you run the app – you should see a blank activity like below.Step 4 Blank App

Adding Test Dependencies

Navigate to your apps build.gradle  file and add the following dependencies. The  testing dependencies that need to be added include Espresso, Mockito, PowerMock and Hamcrest. Retrofit, OkHttp, RxJava and RxAndroid will also be added so we can do effective networking and achieve cleaner code.

 compile 'com.squareup.okhttp3:logging-interceptor:3.4.0-RC1'
    compile 'com.android.support:appcompat-v7:24.1.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha4'

    //Retrofit, RxJava and OkHttp.
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
    compile 'com.squareup.okhttp3:okhttp:3.4.0-RC1'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
    compile 'io.reactivex:rxandroid:1.2.1'
    compile 'io.reactivex:rxjava:1.1.6'
    compile 'com.squareup.picasso:picasso:2.5.2'

    //Dependencies for JUNit and unit tests.
    testCompile "junit:junit:4.12"
    testCompile "org.mockito:mockito-all:1.10.19"
    testCompile "org.hamcrest:hamcrest-all:1.3"
    testCompile("org.powermock:powermock-module-junit4:1.6.2")
    testCompile("org.powermock:powermock-api-mockito:1.6.2")
    testCompile 'com.squareup.okhttp3:mockwebserver:3.4.0-RC1'

    //Dependencies for Espresso
    androidTestCompile 'com.android.support:appcompat-v7:24.1.1'
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    androidTestCompile("com.android.support.test:runner:0.5") {
        exclude module: 'support-annotations'
        exclude module: 'support-v4'
    }
    androidTestCompile("com.android.support.test:rules:0.5") {
        exclude module: 'support-annotations'
        exclude module: 'support-v4'
    }
    androidTestCompile("com.android.support.test.espresso:espresso-intents:2.2.2") {
        exclude module: 'recyclerview-v7'
        exclude module: 'support-annotations'
        exclude module: 'support-v4'
    }
    androidTestCompile('com.android.support.test.espresso:espresso-contrib:2.2.1') {
        exclude module: 'recyclerview-v7'
        exclude module: 'support-annotations'
        exclude module: 'support-v4'

    }

testCompile  is the configuration for unit tests (located in src/test) and androidTestCompile is used for the instrumentation tests (located in src/androidTest). Differences between these two types of tests can be found in Part 1 of this series.

Using Gradle Build Flavors to enable Mocking

In order to enable easy and quick testing of the UI, we won’t be hitting the production APIs for Github. We will mock out responses and emulate different network responses. There are a couple of different ways to achieve this. The way in which I will demonstrate this is by using Gradle product flavors.

Flavors allow you to build different versions of your app, with some source code differences or resource differences. For instance, if you wanted to make a free version of your app and a paid version with more features, using product flavors would be a good way to achieve this.

In this instance, we will create a “Production” and a “Mock” flavor. We could also add a “Staging” flavour if we had a staging environment that we wanted our app to point to. This would allow us to install a production version of your app on a device at the same time as a mock version.

  1. In order to use productFlavors, navigate to your app build.gradle file and add the following into the android{ } section. The following code means that for the mock variant, the applicationId will be different which means I can install both concurrently on one device. For the prod version, the applicationId will be taken from the defaultConfig setting.
    productFlavors {
            prod {
    
            }
            mock {
                applicationId "za.co.riggaroo.gus.mock"
            }
    }
  2. Invoke a Gradle Sync and then on the left hand side of your IDE, you should see a “Build Variants” tab. Open it to see the different flavors of your app that are now available. Gradle Build Variants Android Studio

If you select a different variant, when you click run the build that is deployed to your device will be using that variant’s source set and applicationId .

Running the Unit Tests

In order to run the default unit test (ExampleUnitTest) that exists within the project, you can do it in a few ways:

  • Within Android Studio navigate to and right click on the app/src/test/java  folder. Click “Run Tests”.Running Unit Tests with JUnit in Android Studio
  • Using Gradle: in terminal you can run ./gradlew check

Running the Instrumentation Tests (Requires device or emulator)

In order to run the default instrumentation test (ExampleInstrumentationTest) that exists within the project, you can do it in the following ways:

  • Using Android Studio navigate to and right click on the app/src/androidTest/java  folder. Click “Run All Tests”.Run connected tests android studio
  • Using Gradle: in terminal you can run ./gradlew connectedAndroidTest

How to structure your code to enable easy testing

In order to enable easy testing I am going to use Dependency Injection. You can achieve this without any frameworks (which is what I mostly do) but a lot of people advocate for using Dagger 2 to achieve it. This blog post series is not going to use Dagger.

Create these classes in the following folder structure:Simple Structure Of Android App

I have 4 top level folders for the different parts in the app. This can get more complicated the bigger your app gets. These are the basic folders I like to create:

  • presentation – Within this folder, I create subfolders and group functionality by feature. In this case, I created a folder called search which will hold the view and presenter for the search screen. It will also contain adapters and any other view related code for the search screen.
  • data – This will contain the repositories that will fetch data from the Github API.
  • model – Contains the models that will be used on the presentation layer and the ones that come from the service calls.
  • injection – Classes that will be used for Dependency Injection.

We have covered the setup of the sample app, how to run the different types of tests and the folder structure we will follow. This has now set us on a good path to ensure we can write tests for our app. If you want to see the result of this blog post, check out the corresponding completed code for this blog post here.

The next blog post in this series will go into detail about implementing the feature with tests. Don’t forget to subscribe so you don’t miss the next one!

Subscribe to Blog via Email

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


If you enjoy my posts, please consider buying me a cupcake to keep them coming.
[buy_cupcake]

Thanks to @JoshLiebe for proofreading this post.

9 replies on “Introduction to Automated Android Testing – Part 2 – Setup”

Hi Rebecca,

Great article, I was wandering how do you become a GDE?
I’m from Australia and have been working as Android developer for the past 2 years. Could you please give some advice on how to become GDE.

Hi Shafayat,

What problems are you having with MVP?, it is very similar to MVC design pattern. The main goal of MVP (Model, View, Presenter) is to seperate the code, as Rebecca explains.

M = Model which are objects that represent something such as User.
V = Views are usually Activities or Fragments.
P = Presenter is like a gateway between the model and view, in Rebecca’s example she is going to get the data remotely which then passes through the presenter, which then displays the data in the view.

I hope that helps.

i takes a while. i think learning to test with it is the best way to understand. use MVP, clean architecture and write ur tests. then go back. write a small app with no specific architecutral patten applied and see how easy it is to test.

Comments are closed.