What this post is about?

Using Gradle and Android Studio to run Android tests

Writing unit tests for Android using JUnit4

Writing UI tests with Espresso and the Android Testing Support Library

and the Android Testing Support Library We will be using our last project so if you are new please check out Dagger 2 and MVP Architecture first

Let’s get started

Step 1: Add the necessary dependency

The Android Testing Support library (ATSL) provides a great framework for testing your Android app. It has a JUnit 4-compatible test runner (AndroidJUnitRunner) and functional UI testing through Espresso and UI Automator. You can run tests for these APIs directly in the Android Studio IDE or from the command line, which makes it very easy to integrate them into your development flow.

// Dependencies for local unit tests testCompile "junit:junit:4.12" androidTestCompile 'com.android.support.test:runner:0.5' androidTestCompile 'com.android.support.test:rules:0.5' androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2' androidTestCompile 'com.android.support:support-annotations:24.1.1' compile 'com.android.support.test.espresso:espresso-idling-resource:2.2.2' compile 'com.android.support.test.espresso:espresso-contrib:2.2.2'

Add this

android { ... ... ... ... ... testOptions.unitTests.all { testLogging { events 'passed', 'skipped', 'failed', 'standardOut', 'standardError' } } packagingOptions { exclude 'META-INF/maven/com.google.dagger/dagger/pom.properties' exclude 'META-INF/maven/com.google.dagger/dagger/pom.xml' } }

And add this line in the defaultConfig block

defaultConfig { .... testInstrumentationRunner "" }

If you perform a sync there will be a conflict with the minSdk version for test source set and main source set, so create AndroidManifest.xml in AndroidTest source set

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="${applicationId}"> <uses-sdk tools:overrideLibrary="android.app, android.support.test, android.support.test.rule, android.support.test.espresso, android.support.test.espresso.idling, android.support.test.uiautomator.v18"/> </manifest>

Step 2: Create an IdlingResource file to idle resource when the application makes call to Network

public class EspressoIdlingResource { private static final String RESOURCE = "GLOBAL"; private static CountingIdlingResource mCountingIdlingResource = new CountingIdlingResource(RESOURCE); public static void increment() { mCountingIdlingResource.increment(); } public static void decrement() { mCountingIdlingResource.decrement(); } public static IdlingResource getIdlingResource() { return mCountingIdlingResource; } }

Step 3: Add the following static method in MainActivity.java

@VisibleForTesting public IdlingResource getCountingIdlingResource() { return EspressoIdlingResource.getIdlingResource(); }

Step 4: Add Idling status when network request is made

The CountingIdlingResource is incremented when we make a NetworkRequest and Decrement after the network request finishes.

Note:. When the counter is 0 – it is considered to be idle, when it is non-zero it is not idle.

So in onCreate we increment the counter before calling the loadPost in our Presenter

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (ListView) findViewById(R.id.my_list); list = new ArrayList<>(); DaggerMainScreenComponent.builder() .netComponent(((App) getApplicationContext()).getNetComponent()) .mainScreenModule(new MainScreenModule(this)) .build().inject(this); //Increment the counter before making a network request EspressoIdlingResource.increment(); //Call the method in MainPresenter to make Network Request mainPresenter.loadPost(); }

Similarly, we decrement the counter after the posts are fetched

@Override public void showPosts(List<Post> posts) { //Loop through the posts and get the title of the post and add it to our list object for (int i = 0; i < posts.size(); i++) { list.add(posts.get(i).getTitle()); } //Create the array adapter and set it to list view adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, list); listView.setAdapter(adapter); //Decrement after loading the posts EspressoIdlingResource.decrement(); }

Also, decrement the counter if there is an error (No active Internet or Server error)

@Override public void showError(String message) { //Show error message Toast Toast.makeText(getApplicationContext(), "Error" + message, Toast.LENGTH_SHORT).show(); // If there is no network connection we get an error and decrement the counter because the call has finished EspressoIdlingResource.decrement(); }

Step 5: Write the test case

Create a file MainActivityTest.java in AndroidTest/java source set

@RunWith(AndroidJUnit4.class) @SmallTest public class MainActivityTest { @Rule public ActivityTestRule<MainActivity> mainActivityActivityTestRule = new ActivityTestRule<>(MainActivity.class); @Test public void checkRecyclerView() throws Exception { Espresso.registerIdlingResources(mainActivityActivityTestRule.getActivity().getCountingIdlingResource()); Espresso.onView(ViewMatchers.withId(R.id.my_list)).perform(ViewActions.click()); } }

Step 6: Run the Test by creating a new Run Configuration

Then click on the plus icon and select Android Tests

Configure the test as follows

Name : Test (Can be anything)

Module : app

Specific instrumentation runner : android.support.test.runner.AndroidJUnitRunner

and then click Ok

Now, select the newly create Run Configuration for the Run Menu

Select the device to run the Instrumentation test

Finally, you should see the Test pass. If the test takes too long to finish stop and rerun.

Conclusion

We learnt to set up Android Testing Support library

We used Espresso’s Idling resources feature to wait till the network call happen

We created a custom run configuration to run our tests

Github’s link for code

https://github.com/LadwaAditya/DaggerMVP-Tutorial

Reference