1. Overview
In this codelab, you'll learn how to set up your project in Android Studio for testing, write a Unit Test and run it locally on your development machine and also how to do functional UI testing on the device.
What you’ll learn
- Updating the Gradle build files to include JUnit and the Android Testing Support Library
- Writing Unit Tests which run on the Java VM on your local machine
- Writing Espresso tests which run on the device or emulator
What you’ll need
- Android Studio version 1.2+
- A test device with Android 4.0+
2. Create a new Android Studio project
If you’re launching Android Studio for the first time, select “Start a new Android Studio project” from the Welcome screen. If there’s already a project open, go to File > New > New Project…
The “Create new project” wizard will guide you through the process. On the first screen enter the following:
Setting | Value |
Application name | TestingExample |
Company domain | testing.example.com |
This will ensure your code has consistent naming with the content presented throughout the codelab. You can leave all the other selections on their default setting and simply press Next until your project is created.
You can press theRun button to check if the app runs correctly. You should either select and launch an Emulator from the list or make sure your device is properly attached via USB with debugging enabled.
The app doesn’t do much right now, but you should see a screen showing “Hello world!” and the name of
3. Configure your project for Unit test support
Before you start writing tests, let’s go through a short checklist to make sure that your project is configured correctly.
First, make sure you select “Unit Tests” under Test Artifact in the Build Variants pane.
Next, create the folders
(you can go back to the
test
and test/java
under your module’s src
folder. Note that you cannot do this using the default Android
perspective. You can either use your system’s file explorer to create the necessary folders or switch to the Project
perspective by using the drop down on the top-left of the Project pane. Your final project hierarchy should look like this:(you can go back to the
Android
project perspective for the remainder of this codelab)
And lastly, open your module’s
build.gradle
(Module:app)
file and add JUnit4 to your dependencies section, then click on the Gradle sync button.build.gradle
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.1.1'
testCompile 'junit:junit:4.12'
}
4. Create your first Unit Test
Now that everything is set up, it’s time to start writing your first test. But in order to do that, you will need some code that will be tested. For that purpose, let’s create a very simple Calculator class. This will be what is called our “class under test”.
We’ll add methods for the most common arithmetic operations, like addition and subtraction. Copy and paste the following code into your editor. Don’t worry about the actual implementations yet, just let all methods return 0 (zero) for now.
Calculator.java
package com.example.testing.testingexample;
public class Calculator {
public double sum(double a, double b){
return 0;
}
public double subtract(double a, double b){
return 0;
}
public double divide(double a, double b){
return 0;
}
public double multiply(double a, double b){
return 0;
}
}
Android Studio provides a quick way to create the actual test class for you. Just right click on the Calculator class declaration in your editor and select Go to > Test, then “Create a new test…”
In the dialog window that opens, choose JUnit 4 and select the “setUp/@Before” option, as well as generate test methods for all of our calculator operations.
This should generate a test class skeleton in the correct folder (
app/src/test/java/com/example/testing/testingexample
) with the test methods ready to fill in. Here is an example of how you might test the calculator operations:CalculatorTest.java
package com.example.testing.testingexample;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class CalculatorTest {
private Calculator mCalculator;
@Before
public void setUp() throws Exception {
mCalculator = new Calculator();
}
@Test
public void testSum() throws Exception {
//expected: 6, sum of 1 and 5
assertEquals(6d, mCalculator.sum(1d, 5d), 0);
}
@Test
public void testSubtract() throws Exception {
assertEquals(1d, mCalculator.subtract(5d, 4d), 0);
}
@Test
public void testDivide() throws Exception {
assertEquals(4d, mCalculator.divide(20d, 5d), 0);
}
@Test
public void testMultiply() throws Exception {
assertEquals(10d, mCalculator.multiply(2d, 5d), 0);
}
}
Feel free to copy the code to your editor or write your own tests using assertions provided by the JUnit framework.
5. Running your tests
It’s finally time to run your test! Right click on the
CalculatorTest
class and select Run > CalculatorTest. You can also run the test from the command line, by issuing the following command in your project’s directory:./gradlew test
Regardless of how you run your tests, you should see the output, telling you that 4 out of 4 tests have failed. This is the expected result, as we haven’t implemented the arithmetic operations yet.
Let’s modify the
sum(double a, double b)
method in the Calculator class to return a correct result and re-run the tests. You should see that only 3 out of 4 tests have failed.Calculator.java
public double sum(double a, double b){
return a + b;
}
As an exercise, you can implement the remaining methods to make all tests pass.
6. Configure your project for instrumentation tests
Although there is support for running instrumentation tests in the Android framework, current development efforts are focused around the new
AndroidJUnitRunner
which is released as part of the Android Testing Support Library. The library also contains Espresso, a framework for running functional UI tests. Let’s add both to our project by editing the relevant sections in the module’s build.gradle
file:build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.example.testing.testingexample"
minSdkVersion 15
targetSdkVersion 22
versionCode 1
versionName "1.0"
//ADD THIS LINE:
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
//ADD THESE LINES:
packagingOptions {
exclude 'LICENSE.txt'
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.0.0' //← MAKE SURE IT'S 22.0.0
testCompile 'junit:junit:4.12'
//ADD THESE LINES:
androidTestCompile 'com.android.support.test:runner:0.2'
androidTestCompile 'com.android.support.test:rules:0.2'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.1'
}
All that’s left is to switch to Android Instrumentation Tests in the Build Variants pane. Your project should sync automatically at this point. If it does not, press theGradle sync button.
7. Add a simple interaction to your app
Before we begin testing the UI with Espresso tests, let’s add some Views and a simple behavior to the app. We’ll use an EditText where the user can enter his name and a Button that greets the user using the TextView for output. Open
res/layout/activity_main.xml
and paste the following code:activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:text="@string/hello_world" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<EditText
android:hint="Enter your name here"
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/textView"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Say hello!"
android:layout_below="@+id/editText"
android:onClick="sayHello"/>
</RelativeLayout>
You’ll also need to add the onClick handler in
MainActivity.java
:MainActivity.java
public void sayHello(View v){
TextView textView = (TextView) findViewById(R.id.textView);
EditText editText = (EditText) findViewById(R.id.editText);
textView.setText("Hello, " + editText.getText().toString() + "!");
}
You can now run the app to see it in action and make sure everything works properly. Before you press the Run button, make sure your Run Configuration is not set to run tests from the previous part of the codelab. Use the dropdown and select app. It should look like this:
8. Create and run an Espresso test
In the project overview, find your package name ending with the
(androidTest)
suffix and create a new Java class there. You can name it MainActivityInstrumentationTest
. Paste the following code as its contents:MainActivityInstrumentationTest.java
package com.example.testing.testingexample;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.action.ViewActions;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import org.junit.After;
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.closeSoftKeyboard;
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 MainActivityInstrumentationTest {
private static final String STRING_TO_BE_TYPED = "Peter";
@Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(
MainActivity.class);
@Test
public void sayHello(){
onView(withId(R.id.editText)).perform(typeText(STRING_TO_BE_TYPED), closeSoftKeyboard()); //line 1
onView(withText("Say hello!")).perform(click()); //line 2
String expectedText = "Hello, " + STRING_TO_BE_TYPED + "!";
onView(withId(R.id.textView)).check(matches(withText(expectedText))); //line 3
}
}
The class will be run by the AndroidJUnitRunner and execute the test implemented in the
sayHello()
method. Here’s what the test does, line by line:- First, it finds the view with the ID
editText
and types in the string“Peter”
, then closes the on-screen keyboard. - Next, the test performs a click on the View with text “
Say hello!
”. That’s our Button, for which we didn’t set an id in the layout XML, hence we refer to it by searching for its text. - Finally, the text contents of the TextView are compared with the expected result and the test passes if they match.
You can run the test by right clicking on the class and selecting Run > MainActivityInstrume… (the second one with the Android icon)
This will run your test on the emulator or connected device and, if you watch the screen, you can see the actions (like typing into the EditText) being performed by the runner. See the output in Android Studio for a report on passed and failed tests.
9. Congratulations!
We hope you enjoyed the code lab and are excited to start testing your apps. What next?
- Learn more about local unit tests vs instrumented unit tests.
- Read about setting up the Android Testing Support Library
- Watch these great devbyte videos about Android Studio:
- Check out our testing samples repository on Github
0 comments:
Post a Comment