在这篇文章中,简单介绍下如何在Android Studio中启动测试。书写一个单元测试并在你本地的开发机器上运行,一级如何在设备上做功能UI测试。
你将会学到:
环境:
具体怎么做呢?分为以下几步:
如果你第一次启动Android Studio,从欢迎界面选择“Start a new Android Studio project”。如果已经有一个工程打开了,选择File—->New——>New Project。
这个“Create new project”向导会通过程序指导你。在第一个界面输入如下的内容:
你可以不用管剩下的选项,用默认值即可。一直点下一步直到工程创建成功。
你可以点击运行按钮来检查app是不是正确运行了。
在你开始写测试之前,让我们通过一个小的清单来检查你的工程配置正确。
首先,在Build Variants面板下的Test Artifact一栏中确保你选择了“Unit Tests”。
接下来,创建文件夹test,test/java在你的模块(module)下的src文件夹。注意:你使用默认的Android视图将无法完成这一步。你既可以通过你系统的资源管理器去创建需要的文件夹,或者通过下拉左上角的Project面板切换到Project视图。最后,你的工程目录树看上去应该是这样:
最后,打开你模块(module)下的build.gradle(Module:app)文件,添加JUnit4到dependencies节点下,然后点击Gradle sync按钮。
build.gradle
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.1.1'
testCompile 'junit:junit:4.12'
}
既然万事俱备,是时候开始写你第一个测试代码了。但是为了做这些,你首先需要一些需要被测试的代码(不然测试什么)。出于这个动机,让我们创建一个非常简单的Calculator类,这个类将被称为我们的”class under test”。
我们将添加一些常用的运算操作方法,例如加法和减法。复制粘贴下面的代码到你的IDE中。不要担心这些方法未实现,仅仅让它们return 0就可以了。
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提供了一个快捷的方式来给你创建一个具体的测试类。右键点击Calculator类,选择Go yo—>Test,最后选择”Create a new test…”
在打开的窗口上,选择JUnit 4与”setUp/@Before”选项,同样为我们所有的计算操作实现测试方法。
这将会实现一个测试类,里面包含待补充的测试方法,位于(app/src/test/java/com/example/testing/testingexample)。
这儿有一个你如何测试计算操作的例子。
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);
}
}
最后一刻,运行你的测试代码。邮件点击CalculatorTest类,并选择Run—–>CalculatorTest。你也可以在你的工程目录下使用如下的命令在命令行运行:
./gradlew test
不管你采用何种方式运行你的测试代码,你都应该观察输出,告诉你4/4测试失败了。这儿有一个预期的结果,但是我们并没有实现具体的算数操作。
让我们修改下Calculator类中的这个方法: sum(double a,double b),让它返回正确的计算结果并重新运行测试代码。你讲会看到仅仅3/4测试失败了。
Calculator.java
public double sum(double a, double b){
return a + b;
}
作为练习,你可以实现剩下的方法,让所有的测试都通过。
你可能注意到了Android Studio从没有请求连接到设备或者启动一个模拟器去运行这些测试代码。那是因为这部分测试代码位于src/tests文件夹下,这是本地单元测试运行在你计算机上的Java虚拟机上面。你写测试代码,然后实现这些函数让测试通过,接着添加一些新的更多的tests,这是一个快速循环地工作流,我们称之为测试驱动开发。
另一个需要意识到的是当在本地运行测试的时候Gradle在classpath中提供了你一个android.jar,其中包含Android framework类,但是它们并没有充分利用(你总不能调用Activity的方法作为例子并期待它们工作)。你应该使用一个模拟的框架,例如Mockito来模拟任何一个你需要使用的Android方法。
为了测试运行在设备上的这部分代码并且充分利用Android Framework,继续学习下部分内容。
虽然在Android framework中已经支持运行instrumentation测试,目前的开发工作集中在作为Android测试支持库的一部分发布的新的AndroidJUnitRunner。这个库也包含Espresso。什么是Espresso呢?一个运行UI功能测试的库。让我们通过修改当前模块(module)的build.gradle文件相关的节点来添加它们到我们的工程中。
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'
}
重要的一点:由于一些dependency版本冲突,你可能不得不确保版本为22.0.0的库:com.android.support:appcompat-v7正被使用。同时,Android Studio可能会通知你Build Tools 22.0.1没有被安装。你应该接受建议的修复,这样Studio会安装正确的Build Tools。或者改变build.gradle中的这一行,让它指向你计算机安装过的版本。
接下来要做的就是在Build Variants面板中切换到Android Instrumentation Tests。你的工程应该在这个时候自动同步。如果没有的话,点击Gradle sync按钮。
在我们用Espresso开始UI测试之前,让我们添加一些简单的view以及交互动作到app。我们将使用一个EditText用来接受用户输入他的名字,以及一个Button来响应用户的输入,将结果输出到一个TextView中。打开res/layout/activity_main.xml然后粘贴下面的代码:
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>
添加onClick回调到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() + "!");
}
可以试着运行下app来看事件响应以及其他是否正确工作。在按Run 按钮之前,确保你的Run Configuration不是为了上一部分设置的。通过下拉菜单选择app。它看上去像下面这样:
在项目预览中,找到你的测试包(测试包的命名以androidTest结束),接着创建一个新的java类。你可以命名为MainActivityInstrumentationTest。粘贴下面的代码:
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
}
}
这个类会被AndroidJUnitRunner运行,并执行测试实现方法sayHello()。下面是每一行的具体功能:
怎么运行这个测试呢?右键单击这个类,选择Run—->MainActivityInstrume…(第二个选项,带有Android图标)
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.
这将会运行测试到模拟器或者连接的设备上,如果你观察屏幕,你会发现一些动作(比如在EditText输入的动作)被执行。观察Android Studio中的输出报告,查看是测试通过还是测试失败。