在Android Studio中进行单元测试和UI测试

来源:互联网 发布:经典算法 java 例子 编辑:程序博客网 时间:2024/04/30 03:22

http://www.jianshu.com/p/03118c11c199(转载自简书)

在Android Studio中进行单元测试和UI测试

字数3001 阅读1378 评论2 

本篇教程翻译自Google I/O 2015中关于测试的codelab,掌握科学上网的同学请点击这里阅读:Unit and UI Testing in Android Studio。能力有限,如有翻译错误,请批评指正。如需转载,请注明出处。
Github下载测试源码

目录

  • 在Android Studio中进行单元测试和UI测试 - 1.概述
  • 在Android Studio中进行单元测试和UI测试 - 2.创建新的Android Studio工程
  • 在Android Studio中进行单元测试和UI测试 - 3.配置支持单元测试的工程
  • 在Android Studio中进行单元测试和UI测试 - 4.创建第一个单元测试
  • 在Android Studio中进行单元测试和UI测试 - 5.运行单元测试
  • 在Android Studio中进行单元测试和UI测试 - 6.配置支持Instrumentation测试的工程
  • 在Android Studio中进行单元测试和UI测试 - 7.为app添加简单的交互
  • 在Android Studio中进行单元测试和UI测试 - 8.创建并运行Espresso测试
  • 在Android Studio中进行单元测试和UI测试 - 9.祝贺!

1.概述

在这个codelab中,你将学习如何在Android Studio中配置工程用于测试,在开发机器上编写并运行单元测试,以及如何在手机上做功能UI测试。

你会学到什么

  • 更新包含JUnit和Android Testing Support Library的Gradle构建文件
  • 编写运行在本机Java虚拟机上的单元测试
  • 编写运行在手机或者虚拟机上的Espresso测试

你需要什么

  • Android Studio v1.2+
  • Android 4.0+的测试设备

2.创建新的Android Studio工程

如果是第一次启动Android Studio,从欢迎页选择“Start a new Android Studio project”。如果已经打开了一个工程,选择File>New>New Project...

Create new project”向导会指导整个过程,在第一页输入如下内容:

SettingValueApplication NameTestingExampleCompany demaintesting.example.com

这样会保证你的代码同codelab讲解的内容具有一致的命名。其他的选项都设置为默认,一路点击Next直到工程创建完毕。

点击Run按钮检查app是否运行正常,要么从模拟器列表中选择一个启动,要么确认开启了debug模式的设备通过USB同电脑正确连接。

app目前没有做任何事情,但是屏幕上应该显示“Hello world!”和app的名字。


经常被问及的问题

  • 如何安装Android Studio?
  • 如何开启USB调试?
  • 为什么Android Studio找不到我的设备?
  • Android错误:无法将*.apk安装到设备上:超时?

3.配置支持单元测试的工程

在写测试之前,让我们做下简单的检查,确保工程配置正确。

首先,确认在Build Variants窗口内的Test Artifact中选择了"Unit Tests"。


然后,在工程的src文件夹内创建testtest/java文件夹。需要注意的是,你不能在Android视图下进行这些操作,要么在系统的文件管理器内创建,要么在工程窗口左上方点击下拉菜单选择Project视图。最终的工程结构应该是这样的:


(在codelab的剩余部分,你可以返回继续使用Android工程视图)

最后,打开工程的build.gradle(Module:app)文件,添加JUnit4依赖,点击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'}

当你同步Gradle配置时,可能需要联网下载JUnit依赖。


4.创建第一个单元测试

现在,万事俱备,让我们开始写第一个测试吧。首先,创建一个非常简单的被测类:Calculator类。


然后,向类中添加一些基本的算术运算方法,比如加法和减法。将下列代码复制到编辑器中。不用担心实际的实现,暂时让所有的方法返回0。

Calculator.java

package com.example.testing.testingexample;public class Calculator {    public double sum(double a, double b){        return 0;    }    public double substract(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 to > Test,然后"Create a new test…"


在打开的对话窗口中,选择JUnit4和"setUp/@Before",同时为所有的计算器运算生成测试方法。


这样,就会在正确的文件夹内(app/src/test/java/com/example/testing/testingexample)生成测试类框架,在框架内填入测试方法即可。下面是一个示例:

Calculator.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 testSubstract() throws Exception {        assertEquals(1d, mCalculator.substract(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);    }}

请将代码复制到编辑器或者使用JUnit框架提供的断言来编写自己的测试。


5.运行单元测试

终于到运行测试的时候了!右键点击CalculatorTest类,选择Run > CalculatorTest。也可以通过命令行运行测试,在工程目录内输入:

./gradlew test

无论如何运行测试,都应该看到输出显示4个测试都失败了。这是预期的结果,因为我们还没有实现运算操作。


让我们修改Calculator类中的sum(double a, double b)方法返回一个正确的结果,重新运行测试。你应该看到4个测试中的3个失败了。

Calculator.java

public double sum(double a, double b){    return a + b;}

作为练习,你可以实现剩余的方法使所有的测试通过。

可能你已经注意到了Android Studio从来没有让你连接设备或者启动模拟器来运行测试。那是因为,位于src/tests目录下的测试是运行在本地电脑Java虚拟机上的单元测试。编写测试,实现功能使测试通过,然后再添加更多的测试...这种工作方式使快速迭代成为可能,我们称之为测试驱动开发
值得注意的是,当在本地运行测试时,Gradle为你在环境变量中提供了包含Android框架的android.jar包。但是它们功能不完整(所以,打个比方,你不能单纯调用Activity的方法并指望它们生效)。推荐使用Mockito等mocking框架来mock你需要使用的任何Android方法。对于运行在设备上,并充分利用Android框架的测试,请继续阅读本篇教程的下个部分。


6.配置支持Instrumentation测试的工程

虽然在Android框架内支持运行instrumentation测试,但是目前开发重心主要集中在刚刚发布的作为Android Testing Support Library一部分的新的AndroidJUnitRunner。测试库包含Espresso,用于运行功能UI测试的框架。让我们通过编辑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'}

重要:由于一些依赖版本冲突,你需要确认com.android.support:appcompat-v7库的版本号是22.0.0,像上面的代码片段一样。
另外,Android Studio可能会提醒你Build Tools 22.0.1没有安装。你应该接受修复建议,Studio会为你安装Build Tools或者在build.gradle中把这行修改成已经安装在你电脑的版本。

上面的工作完成后,在Build Variants窗口内切换成Android Instrumentation Tests,你的工程应该自动同步。如果没有,点击Gradle sync按钮。


7.为app添加简单的交互


在使用Espresso进行UI测试前,让我们为app添加一些Views和简单的交互。我们使用一个用户可以输入名字的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>

还需要在MainActivity.java中添加onClick handler:

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


8.创建并运行Espresso测试


在工程的整体视图上,找到以(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)@LargeTestpublic 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()方法。下面将逐行解释都做了什么:

  • 1.首先,找到ID为editText的view,输入Peter,然后关闭键盘;
  • 2.接下来,点击Say hello!的View,我们没有在布局的XML中为这个Button设置id,因此,通过搜索它上面的文字来找到它;
  • 3.最后,将TextView上的文本同预期结果对比,如果一致则测试通过;

你也可以右键点击域名运行测试,选择Run>MainActivityInstrume...(第二个带Android图标的)


这样就会在模拟器或者连接的设备上运行测试,你可以在手机屏幕上看到被执行的动作(比如在EditText上打字)。最后会在Android Studio输出通过和失败的测试结果。

  • 了解更多关于单元测试和instrumentation测试的区别;
  • 了解更多关于设置Android Testing Support Library;
  • 观看下面非常棒的有关Android Studio的视频:

    • Introduction to Android Studio
    • Introducing Gradle (Ep 2, Android Studio)
    • Layout Editor (Ep 3, Android Studio)
    • Debugging and testing in Android Studio (Ep 4, Android Studio)

Github下载测试源码

//-------------------------------------------分割-----------------------------------------

//-------------------------------------------分割-----------------------------------------

//-------------------------------------------分割-----------------------------------------

照着教程做下来已然发现了蛮多问题。

(1)Warning:Conflict with dependency 'com.android.support:support-annotations'. Resolved versions for app (22.2.1) and test app (22.2.0) differ.

http://stackoverflow.com/questions/31807182/android-espresso-issue-dependency-conflict

(2)参看https://developer.android.com/tools/testing-support-library/index.html#setup

<span style="font-size:18px;">dependencies {  androidTestCompile 'com.android.support.test:runner:0.3'  // Set this dependency to use JUnit 4 rules  androidTestCompile 'com.android.support.test:rules:0.3'  // Set this dependency to build and run Espresso tests  androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2'  // Set this dependency to build and run UI Automator tests  androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'}</span>

(3)开始的单元测试JUnit4一直不成功,后来解决build.gadle导入相关包冲突之后就可以了。

总结:(1)https://bintray.com/是jCenter的网站,可以在此网站看看是否有相关的版本,自己在这个网站看JUnit对应的版本。也可以下载相应的jar包。

(2)这次安装Android Studio和Adt后发现,他们的目录竟然不指向同一个目录了,这个要注意了。

Android Studio指向的是C:\Users\Administrator\AppData\Local\Android\Sdk,可以通过File->Project Structure->SDK Location可以看到。

(3)类似的com.android.support.test:rules:0.2和com.android.support.test.espresso:espresso-core:2.2等等包,自己在JCenter去找,

其实是没有找到的,这个看提示指向https://developer.android.com/,然后才知道这些包在support里面,需要更新Android SDK Manager里面的extras

里面的最新内容得到。所以官网还是很重要的。


<span style="font-size:18px;">public class Calculator {    public int sumInteger(int a, int b) {        return a + b;    }    public int substractInteger(int a, int b) {        return a - b;    }    public double sum(double a, double b) {        return a + b;    }    public double substract(double a, double b) {        return a - b;    }    public double divide(double a, double b) {        return a / b;    }    public double multiply(double a, double b) {        return a * b;    }}</span>



<span style="font-size:18px;">public class CalculatorTest {    private Calculator mCalculator;    @Before    public void setUp() throws Exception {        mCalculator = new Calculator();    }    @Test    public void sumInteger() throws Exception { // 无需以test方法开头        assertEquals(7, mCalculator.sumInteger(4, 3));    }    @Test    public void testSum() throws Exception {        assertEquals(2d, mCalculator.sum(4d, 3d), 0);    }    @Test    public void testSubstract() throws Exception {    }    @Test    public void testDivide() throws Exception {    }    @Test    public void testMultiply() throws Exception {    }    @Test    public void testSubstractInteger() throws Exception {    }}</span>


(1)单元测试中,其实JUnit4并不需要非要方法以test开头,这里已经展示了。

(2)

assertEquals(2d, mCalculator.sum(4d, 3d), 0);
这里的第三个参数其实表明范围,也就是一个范围差值,在范围内都可以。

(3)当我们新增一个方法的时候,还可以照原来生成这个CalculatorTest.java的方法,生成对应方法的测试,当然也是可以手动加的。

(4)

<span style="font-size:18px;">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;</span>
<span style="font-size:18px;">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</span>

这里的onView()、witdId()、perform()、closeSoftKeyboard()方法等方法都是espresso。

(5)这个需要版本在Api18以上才行。

0 0
原创粉丝点击