Testing in Android : Part 5 : Automated UI Test using Espresso

ANDROID UI TESTING USING ESPRESSO:


UI testing can be done by a human tester performing a set of user operations on the Application and verify that it is behaving as expected. Main problem with this approach is that it is time consuming, tedious and error-prone. Instead, we can use automated approach to simulate user actions on the application easily in a repeatable manner.

  • test code is written inside (src/androidTest/java) folder. ( same folder we have used for Instrumented Unit Tests here ).
  • Create one new class AutomatedUiTest.java inside this folder..
  • For testing android applications, we can have two different types of automated UI tests :
    • Test for single app : This type of test is performed to check only the test application .
    • Test for multiple apps : This type of test is performed to test the behaviour of interactions between test application and other user applications and/or between system applications. e.g. we are developing a camera application and we want to check if it can share photo to other photo viewer application or not.
Android Testing Support Library includes a testing framework called Espresso that we can use to write UI tests for devices with Android 2.2 and higher. Espresso works with AndroidJUnitRunner test runner .

SETUP :

include the following dependency to your build.gradle file :
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
Espresso has 3 components :
  1.  Find view we want to test in an Activity : By calling onView() method or if you are using AdapterView , use onData() method.
  2. Perform Action : ViewInteraction and DataInteraction object is returned for onView() and onData() method. we can call perform() method on these objects to pass a user action .
  3. Verify result : Use ViewInteraction.check() method to check a view state.

e.g :

onView(withId(R.id.id_view)).perform(click()).check(matches(isDisplayed()));

Example :
 
In this tutorial, we will create one simple login page, input username and password and finally click on the “login” button. One text view will be used to display success or failure.
  1. Update your activity_main.xml file as below :

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#303F9F"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">
    <android.support.design.widget.TextInputLayout
    android:id="@+id/layout_email"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textColorHint="#B2EBF2">
    
    <EditText
    android:id="@+id/editTextEmail"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="email"
    android:inputType="textEmailAddress"
    android:textColor="#E0F7FA" />
    </android.support.design.widget.TextInputLayout>
    
    <android.support.design.widget.TextInputLayout
    android:id="@+id/layout_password"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/layout_email"
    android:textColorHint="#B2EBF2"
    >
    
    <EditText
    android:id="@+id/editTextPassword"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="45dp"
    android:hint="password"
    android:inputType="textPassword"
    android:textColor="#E0F7FA" />
    </android.support.design.widget.TextInputLayout>
    
    <Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentEnd="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentRight="true"
    android:layout_alignParentStart="true"
    android:layout_below="@+id/layout_email"
    android:layout_marginTop="104dp"
    android:background="#00BCD4"
    android:text="Login"
    android:textColor="#E0F7FA" />
    
    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:inputType="text"
    android:layout_below="@+id/button"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="50dp"
    android:textColor="#E0F7FA"
    android:id="@+id/textViewResult" />
    </RelativeLayout>
  1. Add the following to your MainActivity.java

    mLoginButton = (Button) findViewById(R.id.button);
    mEmailET = (EditText) findViewById(R.id.editTextEmail);
    mPasswordET = (EditText) findViewById(R.id.editTextPassword);
    mResultTV = (TextView) findViewById(R.id.textViewResult);
    mLoginButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
    if (mEmailET.getText().toString().equals("codevscolor@gmail.com") && mPasswordET.getText().toString().equals("password"))
    mResultTV.setText("success");
    else
    mResultTV.setText("failed");
    }
    });
    }
  2. Update AutomatedUITest.java as :

    import android.support.test.filters.LargeTest;
    import android.support.test.rule.ActivityTestRule;
    import android.support.test.runner.AndroidJUnit4;
    import org.junit.Before;
    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    
    import static android.support.test.espresso.Espresso.onView;
    import static android.support.test.espresso.action.ViewActions.click;
    import static android.support.test.espresso.action.ViewActions.typeText;
    import static android.support.test.espresso.assertion.ViewAssertions.matches;
    import static android.support.test.espresso.matcher.ViewMatchers.withId;
    import static android.support.test.espresso.matcher.ViewMatchers.withText;
    
    @RunWith(AndroidJUnit4.class)
    @LargeTest
    public class AutomatedUITest {
    
    private String mEmail;
    private String mPassword;
    private String mSuccessMsg;
    
    @Rule
    public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(
    MainActivity.class);
    
    @Before
    public void initUserNamePassword() {
    mEmail = "codevscolor@gmail.com";
    mPassword = "password";
    mSuccessMsg = "success1";
    }
    
    @Test
    public void login_MainActivity() {
    
    onView(withId(R.id.editTextEmail))
    .perform(typeText(mEmail));
    
    onView(withId(R.id.editTextPassword)).perform(typeText(mPassword));
    
    onView(withId(R.id.button)).perform(click());
    
    // Check if the result is success or not
    onView(withId(R.id.textViewResult))
    .check(matches(withText(mSuccessMsg)));
    }
    
    }
Here , we are using ActivityTestRule to write this test.  Using this, the testing framework will launch the activity before each test method (@Test), Before test, it will run @Before method, and after test is completed, it will run @After and shut down the Activity.
 
To run this test, right click on “AutomatedUITest” -> Run “AutomatedUITest” -> select device or emulator and click OK.
 
This sample project is shared on Github. If you love this tutorial, do like codevscolor facebook page and subscribe to the newsletter. 🙂

Testing in Android : Part 4 : Instrumented Unit Test

Instrumented Unit Tests :

These are unit tests that run on real devices instead of JVM . Using instrumented Unit Tests, we can have real implementation of an Android Framework component like SharedPreferences objects, context of an Activity etc. Also , we will not have to mock any objects.1.  Add the following Dependencies :

androidTestCompile 'com.android.support:support-annotations:23.4.0'
androidTestCompile 'com.android.support.test:runner:0.4.1'
androidTestCompile 'com.android.support.test:rules:0.4.1'
// Optional -- Hamcrest library
androidTestCompile 'org.hamcrest:hamcrest-library:1.3'

  note that we are using androidTestCompile as instrumented tests will be inside androidTest folder.

 

 

 

 

2.  Specify AndroidJUnitRunner as the default test instrumentation runner in your build.gradle file :

android {
    defaultConfig {
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
}

3.  Create a Class “InstrumentedUnitTest” inside src/androidTest/java/com.packagename folder and add @RunWith(AndroidJUnit4.class) annotation at the beginning of this class.

4.  Create one test inside this class . Final class will be like below.

import android.content.Context;
import android.content.SharedPreferences;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class InstrumentedUnitTest {

 private final String prefName = "TEST_PREF";


 @Test
 public void test_sharedPref(){
 Context mContext = InstrumentationRegistry.getContext();

 SharedPreferences mSharedPreferences = mContext.getSharedPreferences(prefName,Context.MODE_PRIVATE);
 SharedPreferences.Editor editor = mSharedPreferences.edit();

 editor.putString("key", "value");
 editor.apply();

 SharedPreferences mSharedPreferences2 = mContext.getSharedPreferences(prefName, Context.MODE_PRIVATE);
 assertThat("value", is(mSharedPreferences2.getString("key", null)));
 
}

}

 5.  Thats it.Run this test. Right click on this file -> Run “InstrumentedUnitTest” ->select your device/emulator ( remember , we are running this test on a real device, not like our previous unit testing tutorials) and click “OK”.

One message will appear like below if everything works fine :

unit_test_android

 

 

 

 

That’s it 🙂 . If you love this tutorial , do like our facebook page and subscribe to our news letter.