android 测试教程(转)

来源:互联网 发布:mysql offset用法 编辑:程序博客网 时间:2024/06/05 02:14

http://www.imobilebbs.com/wordpress/archives/2764


Android测试教程(1):概述

Published on 2011 年 07 月 31 日

测试也是开发过程中一个重要组成部分,Android开发环境集成一个测试框架可以用来测试Android应用的各个方面,单元测试,UI测试等。

本教程基于Android 开发教程英文版。

基本概念包括

  • Android测试的基础知识
  • Activity Testing 侧重于Activity的测试,介绍了如果使用Instrumentation 在正常Activity生命周期之外来控制Activity,然后测试Activity的特定的功能和测试UI的一些技巧。
  • Content Provider Testing  侧重测试Content  Provider。
  • Service Testing 侧重测试Service。
  • 需要测试的内容等。

以及在Eclipse ADT开发环境下如何创建一个测试项目和Android开发工具提供的一些测试工具。在阅读本测试教程之前,你需要有Android开发的一些基本知识,可以参见Android开发教程 ,此外需要了解一些JUnit的基本概念 。

并对ApiDemo中的测试示例进行解析。


Android测试教程(2):测试基础

Published on 2011 年 08 月 10 日

Android测试框架(Android Testing Framework)为Android开发环境的一个组成部分,可以用来测试Android的各个方面,从单元测试到框架测试到UI测试等。

其主要功能有:

  • Android测试框架基于JUnit,因此可以直接使用JUnit 来测试一些与Android平台不是很相关的类,或者使用Android的JUint 扩展来测试Android组件,如果你刚开始接触Android 测试,可以先从AndroidTestCase写一些通用的测试用例,然后再写较复杂的测试用例。
  • Android JUint 扩展提供了对Android特定组件(如Activity,Service)的测试支持,这些扩展类提供了一些辅助方法来帮助创建测试使用的“桩”类或方法。
  • 创建的测试包包含中一个测试包中,这个测试包和主应用程序包具有类似的结构,创建测试包的步骤和创建Android应用的方法基本类似。
  • Eclipse的ADT包含了创建测试用例的SDK工具,并提供用于和其它IDE集成的命令行工具。这些工具可以从被测试的应用程序包读取所需信息用于创建测试项目的build 文件,mainfest 文件和文件目录结构等。
  • SDK也提供了一个moneyrunner (一个python应用)可以模拟用户按键事件来测试UI。

下图为Android测试框架的一个总结:


Android测试教程(3):测试项目

Published on 2011 年 08 月 18 日

Android的编译和测试工具需要测试项目组织符合预订的结构:分别为Test case 类,Test case 包以及测试项目。

JUnit 为Android的测试的基础,一般来说,一个JUint测试为一个用来测试一个应用某一部分的语句。 你可以将多个测试Test方法组织起来构成一个测试用例(Test case),多个测试用例可以构成Test Suites 。 每个Test方法相对独立,一个测试类Test class包含一组相关的Test 或其它辅助方法。

在Android平台上,你可以使用测试工具调入Test Package和所要测试的应用,然后执行Test Runner来运行测试用例。

使用Eclipse ADT 工具创建测试项目的方法:

1. 在创建应用的同时创建测试项目,如下图

选中Create a Test Project ,ADT自动为应用创建对应的测试项目

2. 导入已有的测试项目,并和被测试的应用关联。

Android SDK 自带ApiDemo,并带有其对应的测试项目ApiDemos->Test. 打开ApiDemos->Test 的方法如下,首先是选中Build Target (比如Android 2.2),然后选择Create project from existing sample, 从下拉列表中选择ApiDemos ->Tests (注意你要先创建ApiDemosAndroid ApiDemos示例解析(1):创建ApiDemo示例)

将ApiDemos->tests 和ApiDemos 关联起来:

修改ApiDemos->tests 测试项目的属性,在Java Build Path 的项目Projects 中添加ApiDemos

你最好使Eclipse 工具创建测试项目:

  • 自动为你的测试项目设置使用InstrumentationTestRunner 作为运行Test Package的Test Runner,测试项目必须使用InstrumentationTestRunner 或其子类做为Test Package的runner.
  • 为测试项目创建合适的项目名称和测试包名称,比如你需要测试的应用的包名称为com.mydomain.myapp 则自动创建的测试包名为com.mydomain.myapp.test ,从测试包名可以很容易找到对应的应用程序包名称。
  • 自动创建合适的build 文件,mainifest 文件和文件目录结构。

建议使用的文件目录结构可以如下所示:

MyProject/
—–AndroidManifest.xml
—–res/
——–… (resources for main application)
—–src/
——–… (source code for main application) …
—–tests/
———-AndroidManifest.xml
———-res/
————-… (resources for tests)
———-src/
————-… (source code for tests)


Android测试教程(4):测试相关API

Published on 2011 年 08 月 21 日

Android的测试框架相关的API主要定义在三个包中:

  • android.test  用于编写Android测试用例
  • android.test.mock  定义了方便测试用的测试“桩”类
  • android.test.suitebuilder  运行测试用例的Test Runner类

Android 测试API 是基于JUnit 扩展而来,并添加了与Android平台相关的测试API。

JUnit

你可以直接使用JUnit中相关API编写一些和平台无关的测试用例(基于TestCase), Android 测试API中提供了一个TestCase的子类AndroidTestCase ,可以用来编写一些Android相关的对象的测试用例,AndroidTestCase 支持一些和平台相关的setup,teardown 以及setup 方法。

你也可以直接使用JUnit 的Assert 方法 显示测试结果,这些Assert方法可以通过比较预期的值和实际的值,如果不同可以排除异常。Android 测试API扩展了一些Assert方法用于支持和Android平台相关的比较。

要注意的是,Android 测试API支持JUnit 3 代码风格,而不支持JUnit 4 代码风格,也只能使用InstrumentationTestRunner 来运行测试用例。

Instrumentation

Android 的Instrumentation 提供了一些“钩子”方法连接到Android操作系统中,可以独立控制Android组件(Activity,Service等)的生命周期,并可以控制Android如何调用一个应用。

在通常情况下(普通的Android应用),Android的activity,Service等的生命周期是由
Android操作系统来控制的。 比如一个Activity 的生命周期开始于onCreate (由某个Intent激活),然后是onResume. 可以参见Android简明开发教程五:Activities。 应用程序本身无法直接控制这些生命周期状态的切换。但使用Instrumatation API时你可以直接调用这些方法。

Instrumentation API 也可以支持强制某个应用和另一个已经在运作的应用运行在同一个进程中,这在通常的情况下是不可能实现的。

使用Instrumentation API 你可以直接调用Activity或是Service的生命周期回调函数,从而可以让你运行一步一步的运行Activity或是Service的生命周期函数。如下例显示了如何使用Instrumentation API来测试Activity 保持和恢复State。

// Start the main activity of the// application under testmActivity = getActivity();// Get a handle to the Activity object's//main UI widget, a SpinnermSpinner= (Spinner)mActivity .findViewById(com.android.example.spinner.R.id.Spinner01);// Set the Spinner to a known positionmActivity.setSpinnerPosition(TEST_STATE_DESTROY_POSITION);// Stop the activity - The onDestroy()//method should save the state of the SpinnermActivity.finish();// Re-start the Activity - the onResume()//method should restore the state of the SpinnermActivity = getActivity();// Get the Spinner's current positionint currentPosition = mActivity.getSpinnerPosition();// Assert that the current position is the//same as the starting positionassertEquals(TEST_STATE_DESTROY_POSITION, currentPosition);

其中关键的一个方法是getActivity(),只有调用getActivity()后被测试的activity才会启动。此外Instrumentation API允许把测试项目和被测试的应用项目运行到同一个进程中,从而在测试代码中可以直接调用被测试应用的方法和访问其成员。

Test case 相关类

Android提供了多个由Testcase或Assert派生而来的子类以支持Android平台相关的setup,teardown 和其它辅助方法。

  • AndroidTestCase 为一Android平台下通用的测试类,它支持所有JUnit的Assert方法和标准的setUp 和tearDown 方法,并可以用来测试Android permission 。
  • 组件相关的测试类如测试activity, Content provider ,Service 相关的测试类,Android没有提供单独的用来测试BroadcastReceiver 的测试类,而是可以通过发送Intent对象来检测Broadcast Receiver的反应结果来测试BroadcastReceiver。
  • ApplicationTestCase 可以用来测试Application 对象。
  • InstrumentationTestCase 如果你要使用Instrumentation API,那么你必须使用InstrumentationTestCase或其子类。

Assertion classes

Android测试中可以使用JUnit中提供的Assert方法来显示测试结果。除此之外,Testing API还提供了MoreAsserts 和ViewAsserts 类。其中MoreAsserts支持更多的比较方法包括RegEx(正则)比较等。ViewAsserts 可以用来校验UI View。

Mock object classes

android.test.mock 包中定义一些测试“桩”类,如MockApplication,MockContentProvider ,MockContext,MockCursor, MockPackagManager等用例帮助测试。

后面将具体介绍如何使用这些API来编写测试用例。


Android测试教程(5):第一个测试项目HelloWorldTest

Published on 2011 年 08 月 21 日

本例介绍创建一个测试项目的一般步骤和编写测试用例的基本方法。

为简单起见,创建一个HelloWorld应用,带有一个Greeting类,其定义如下:

public class Greeting { private String name; public Greeting(String name){ this.name=name; } public String getGreetings(){ return "Hello," +name; }}

测试项目打算来测试这个Greeting 类的getGreetings的方法,比如说,创建Greeting(“World”) ,预期的getGreetings 的值应为”Hello,World”。我们可以使用JUnit框架来编写一个测试用例。

这里我们在创建HelloWorld的项目的同时创建一个测试项目,参见Android测试教程(3):测试项目

可以看到新创建的测试项目名称为HelloWorldTest ,并在src 中创建了com.pstreets.demo.test 文件夹(和HelloWorld 应用的com.pstreets.demo 包相对应)。但src 还没有任何代码。

可以看到HelloWorldTest 属性的Java Build Path-> Projects 中引用的Project为HelloWorld, 表示在HelloWorldTest 项目中可以引用HelloWorld 项目中的类。

然后在HelloWorldTest的src 的com.pstreets.demo.test 中添加一个AllTests.java,其定义如下:

public class AllTests extends TestSuite { public static Test suite() { return new TestSuiteBuilder(AllTests.class) .includeAllPackagesUnderHere() .build(); }}

使用TestSuiteBuilder 指明所有该包和其子包中定义的TestCase都为最终TestSuite 的一部分(需要被运行的测试)。

AllTests.java 一般可以不用修改的应用到大部分的测试项目中,如果有特殊需要,可以使用android.test.suitebuilder 的类定义那些Testcase 需要包含到最终的测试包(Test Suite)中.

定义了AllTests.java ,这个测试项目就基本完整了,也可以运行了,只是还没有定义任何测试用例(Test case) 。

这里定义一个GreetingTest ,用于测试Greeting 类:

public class GreetingTest extends TestCase { Greeting greeting; @Override public void setUp(){ greeting=new Greeting("World"); } @Override public void tearDown(){ } public void testGetGreeting() { assertTrue(greeting.getGreetings() .compareToIgnoreCase("Hello,World")==0); }}

其实对于与这个例子setUp和tearDown 不是必须的,如果多个TestCase 使用同一组测试数据,可以在setUp 中创建这些测试数据,JUnit 中运行每个TestCase 前会运行setUp ,运行TestCase 后会执行tearDown 。

JUnit 把以test开头的方法作为一个实例,也可以使用annotation @Test 表示一个方法为测试方法。

GreetingTest 由TestCase 派生,因为这里测试是一个普通Java类(和Android 平台无关),也可以使用AndroidTestCase 作为基类。

testGetGreeting 使用assertTrue 来检测测试结果,预期的getGreetings()的值为”Hello,World” ,如果为true ,表示测试通过。

以Android JUint Test 的方式运行HelloWorldTest

运行HelloWorldTest 时,Android测试环境会自动启动HelloWorld ,并在JUint 窗口显示最终测试结果。

在开发应用过程中,可以一边编写应用,一边编写测试用例。


Android测试教程(6):测试Activity

Published on 2011 年 08 月 22 日

Activity的测试非常依赖于Android的Instrumation 框架,和Android其他组件不同的是,Activity具有复杂的生命周期回调函数(如onCreate, onStart 等) ,通常情况下除通过Instrumation 接口外不能直接调用这些回调函数。

  • 测试Activity的基本测试类为InstrumentationTestCase,它提供了Instrumentation接口给TestCase的子类。 为了支持Activity测试,InstrumentationTestCase提供了下面功能:
  • 生命周期控制: 使用Instrumentation,你可以启动,暂停,中止被测试的Activity。
  • Dependency Injection : Instrumentation允许创建一些Mock对象如Context,Application来帮助测试Activity,从而帮助你控制测试环境并和实际的应用的其他部分隔离开来。你也可以定制一些Intent以启动Activity。
  • 用户界面交互: 你可以使用Instrumentation向UI发送按键和触摸事件。

下面几个为主要的用于测试Activity由TestCase派生而来的测试类:

  • ActivityInstrumentationTestCase2  通常用于多个Activity的功能测试,它使用正常的系统框架来运行Activity(使用应用程序本身),并使用正常系统Context (非Mock)来测试Activity的功能。 允许你创建一些Mock Intent 用来测试Activity的响应。要注意的是,这种TestCase不允许使用Mock的Context和Application对象测试,也就是说你必须使用和应用程序实际运行的环境来测试。
  • ActivityUnitTestCase 通常用来测试单独Activity。在启动被测试的Activity之前,你可以Inject一个假的Context或是Application ,使用这个Mock的Context中一个隔离环境中运行被测试的Activity。通常用于Activity的单元测试,而不和Anroid系统进行交互。
  • SingleLaunchActivityTestCase  用于测试单个Activity,和ActivityUnitTestCase不同的是,它只运行setUp 和tearDown 一次,而不是在运行testCase 中每个Test Method前后运行setup 和tearDown ,它可以保证运行多个测试之间fixture 不会被重置,从而可以用来测试一些有关联的方法。

本篇和后面几篇介绍Activity,Service,Content Provider 测试的基本概念和相关类,之后则结合ApiDemo->Tests 为例具体介绍这些类的用法。


Android测试教程(7):测试Content Provider

Published on 2011 年 08 月 26 日

Content Provider 为不同的应用访问数据提供了统一的接口,本篇介绍Android测试包中用于测试Content Provider 的相关知识。

Android 测试包中用于测试Content Provider的基本类为ProviderTestCase2, 允许你在一个隔离环境下来测试Content Provider。 并提供了一些Mock类如IsolatedContext ,MockContentResover 来辅助测试。

和其它测试一样,对于Content Provider测试也是通过InstrumentationTestRunner 来进行的。

编译测试代码的一般方法是通过派生ProviderTestCase2 (为AndroidTestCase  的子类),因此可以使用JUnit和Android平台相关的方法来测试Content Provider。

可以参见后面的实例来了解如何测试Content Provider。

Android测试教程(8):测试Service

Published on 2011 年 08 月 27 日

Android 测试框架也提供对Service测试的支持,基本类为ServiceTestCase,因为Service类通常假定和它是和Client是分开使用的,因此你可以无需使用Instrumentation 来测试Service。

当你设计一个Service时,你应该考虑测试用例中如何检查Service的当前状态,比如你在onCreate ,onStartCommand 中启动一个Service,一般没有一个全局变量来表示Service是否成功,你可能需要自己定义一个全局变量用于测试用例中。

ServiceTestCase 中提供getService() 可以取得当前被测试的Service对象。

ServiceTestCase 为AndroidTestCase的子类,因此可以测试和Permission 相关的功能,并提供Mock的Application 和Context 对象为测试Service提供了一个隔离的测试环境。

后面提供具体例子。


Android测试教程(9):ApplicationTestCase示例

Published on 2011 年 08 月 28 日

前面介绍了Android测试的一些理论知识,从本篇开始的几篇将结合ApiDemoTest示例来介绍Android测试的实例。在此之前可以参照Android测试教程(3):测试项目 创建ApiDemos->tests 测试项目,本项目测试用来测试ApiDemos,主要目的是介绍Android测试框架的使用方法。

当然要测试ApiDemos,事先要创建好项目ApiDemos。下图显示了创建好ApiDemos->Tests后,ApiDemos->Tests中所含的Java类:

Android测试项目也是一个Android应用项目,其基本使用方法和开发一般的Android应用非常类似,Android测试项目主要是利用Android测试框架编写测试用例来测试对应的Android应用的各个方面。

其中AllTests.java 定义如下:

public class AllTests extends TestSuite { public static Test suite() { return new TestSuiteBuilder(AllTests.class) .includeAllPackagesUnderHere() .build(); }}

使用TestSuiteBuilder 指明所有该包和其子包中定义的TestCase都为最终TestSuite 的一部分(需要被运行的测试)。

AllTests.java 一般可以不用修改的应用到大部分的测试项目中,如果有特殊需要,可以使用android.test.suitebuilder 的类定义那些Testcase 需要包含到最终的测试包(Test Suite)中.

ApiDemosApplicationTests 测试介绍ApplicationTestCase的基本使用方法。

下图为ApplicationTestCase 的继承关系:

ApplicationTestCase 主要用来测试Application 类,提供了对Application类生命周期方法的基本支持,并可以支持一些dependency injection 以帮助构造测试Application的的环境。

Application Lifecycle 支持, 每个Application运行 都遵循一定的顺序(生命周期方法),ApplicationTestCase提供下面方法来支持对Application生命周期方法的测试:

  • 只有当测试用例调用createApplication()后才会执行Application 的onCreate 方法,从而使得你有机会在调用Application的onCreate方法之前对测试框架做些调整。
  • 当测试用例结束时,测试用例的tearDown 方法会被调用,然后会调用Application 的onDestroy()方法停止和销毁Application.

Dependency Injection 每个Application都依赖于运行它的Context 对象,Android测试框架允许你注入一个Mock的或者孤立的context 对象,以实现真正的单元测试,如果只是想做一般的测试,你的Application方法将被注入全功能的Context对象,你可以使用setContext 来注入你定义的Mock 的Context对象,setContext 必须在createApplication 之前调用。测试框架提供了如MockContext, RenamingDelegatingContext, ContextWrapper 来帮助你构造用于测试Applicaton的Context对象。

本例的代码如下:

public class ApiDemosApplicationTests extends ApplicationTestCase<ApiDemosApplication> { public ApiDemosApplicationTests() { super(ApiDemosApplication.class); } @Override protected void setUp() throws Exception { super.setUp(); } @SmallTest public void testPreconditions() { } /** * Test basic startup/shutdown of Application */ @MediumTest public void testSimpleCreate() { createApplication(); }}

有几个新知识

1. @SmallTest 和@MediumTest标注

Android测试框架可以使用@SmallTest,@MediumTest和@LargeTest 来标注测试方法,这些分类划分主要是根据测试访问数据的位置,如本地,SD卡,网络,下表为通常划分测试等级的基本方法:

FeatureSmallMediumLargeNetwork accessNolocalhost onlyYesDatabaseNoYesYesFile system accessNoYesYesUse external systemsNoDiscouragedYesMultiple threadsNoYesYesSleep statementsNoYesYesSystem propertiesNoYesYesTime limit (seconds)60300900+

2. testPreconditions

testPreconditions 测试主要用来运行其它测试方法之前来校验Application 对象的初始化情况,和setUp类似,但和setUp 不同的是,testPreconditions只会被运行一次,而setUp通常在执行每个测试方法之前都会运行一次,一般需把它做为Application第一个测试方法,但由于JUnit使用Reflection 来取得测试方法,因此并不一定能保证testPreconditions一定在其它测试方法之前运行。

testSimpleCreate 为测试Application 的测试方法,调用createApplication 会触发Application 的onCreate 方法,测试结束后,执行tearDown ,然后调用Application 的onDestroy 方法,如果Application 的onCreate, onDestroy 运行抛出异常的话,则本测试方法失败,否则表示测试通过。

ApplicationTestCase 还提供了一个terminateApplication 中止Application,可以测试Application 的onTerminate 方法。



Android测试教程(10):ActivityInstrumentationTestCase2示例

Published on 2011 年 08 月 29 日

ActivityInstrumentationTestCase2 主要用来测试一个或多个Activity的功能测试,使用和最终应用同样的运行环境来测试Activity的功能。可以使用正常系统Context (非Mock)来测试Activity的功能。 并允许你创建一些Mock Intent 用来测试Activity的响应。要注意的是,这种TestCase不允许使用Mock的Context和Application对象测试,也就是说你必须使用和应用程序实际运行的环境来测试。

ActivityInstrumentationTestCase2 的继承关系如下图所示:

它的getActivity() 方法可以取得被测试的Activity的实例对象。

ApiDemosTest 的代码如下:

public class ApiDemosTest extends ActivityInstrumentationTestCase2<ApiDemos> { public ApiDemosTest() { super(ApiDemos.class); } public void testActivityTestCaseSetUpProperly() { assertNotNull("activity should be launched successfully", getActivity()); }}

测试方法testActivityTestCaseSetUpProperly 使用getActivity() ,主要目的是测试本测试的Activity能否正常启动,测试getActivity() 是否非空。

此外ActivityInstrumentationTestCase2 还提供了两个方法:

  • setActivityInitialTouchMode(boolean) 在启动Activity之前设置TouchMode
  • setActivityIntent(Intent) 可以设置启动Activity的Intent 对象来测试Activity


Android测试教程(11):ActivityUnitTestCase示例

Published on 2011 年 08 月 30 日

ActivityUnitTestCase 通常用来测试单独Activity。在启动被测试的Activity之前,你可以Inject一个假的Context或是Application ,使用这个Mock的Context中一个隔离环境中运行被测试的Activity。通常用于Activity的单元测试,而不和Anroid系统进行交互。

ActivityUnitTestCase 的类继承关系如下图:

应该要注意的是,作为单纯的单元测试,被测试的Activity 不运行在一般应用运行的环境中也不和其它Activity产生交互。在这种情况下,不能调用下面的方法,如果调用一般会抛出异常:

createPendingResult(int, Intent, int)
startActivityIfNeeded(Intent, int)
startActivityFromChild(Activity, Intent, int)
startNextMatchingActivity(Intent)
getCallingActivity()
getCallingPackage()
createPendingResult(int, Intent, int)
getTaskId()
isTaskRoot()
moveTaskToBack(boolean)

下面的方法可以调用,但一般不起任何作用,你可以使用getStartedActivityIntent()和getStartedActivityRequest() 来检查参数值。

startActivity(Intent)
startActivityForResult(Intent, int)

下面的方法也可以调用,一般也无效果,可以使用isFinishCalled() 和getFinishedActivityRequest检查传入的参数。

finish()
finishFromChild(Activity)
finishActivity(int)

ForwardingTest 的代码如下:

public class ForwardingTest extends ActivityUnitTestCase<Forwarding> { private Intent mStartIntent; private Button mButton; public ForwardingTest() { super(Forwarding.class); } @Override protected void setUp() throws Exception { super.setUp(); mStartIntent = new Intent(Intent.ACTION_MAIN); } @MediumTest public void testPreconditions() { startActivity(mStartIntent, null, null); mButton = (Button) getActivity().findViewById(R.id.go); assertNotNull(getActivity()); assertNotNull(mButton); } @MediumTest public void testSubLaunch() { Forwarding activity = startActivity(mStartIntent, null, null); mButton = (Button) activity.findViewById(R.id.go); mButton.performClick(); assertNotNull(getStartedActivityIntent()); assertTrue(isFinishCalled()); } @MediumTest public void testLifeCycleCreate() { Forwarding activity = startActivity(mStartIntent, null, null); getInstrumentation().callActivityOnStart(activity); getInstrumentation().callActivityOnResume(activity); getInstrumentation().callActivityOnPause(activity); getInstrumentation().callActivityOnStop(activity); }}

在setUp 中,创建了一个Mock Intent 对象mStartIntent 用于测试Activity。

按惯例测试方法testPreconditions 通常作为第一个测试方法,如果该方法Fail的话,表示测试所需的条件不满足,此时其它测试一般也会Fail 。但这个方法并不一定是第一个运行。

testSubLaunch 可以测试当前Activity能否成功启动其它Activity,方法getStartedActivityRequest 返回 当前Activity调用startActivityForResult(Intent, int) 的request code. 方法isFinishCalled 将在当前activity 调用finish()或finishActivity, finishFromChild 后返回true. Forwarding 示例参照Android ApiDemos示例解析(7):App->Activity->Forwarding

testLifeCycleCreate 测试Activity的生命周期回调函数,使用getInstrumentation取的Instrumentation 对象,通过Instrumentation对象可以调用Activity对应的生命周期回调函数来测试Activity的onCreate, onStart,onResume 等方法。

ActivityUnitTestCase 还提供了sendKeys 方法模拟按键事件,可以用来测试UI。


Android测试教程(12):ServiceTestCase示例

Published on 2011 年 08 月 31 日

ServiceTestCase 为测试Service提供了一个可控的测试环境,它提供对Service 生命周期的基本支持,并可以通过注入一些依赖对象来控制测试环境以便测试Service。

ServiceTestCase的类继承如下图所示:

Service Lifecycle 支持, 每个Service运行 都遵循一定的顺序(生命周期方法),ServiceTestCase提供下面方法来支持对Service生命周期方法的测试:

  • 每个测试方法调用之前首先会执行setUp 方法,setUp 的基本实现是取得系统Context ,如果你要重载setUp 的话,注意在第一行加上super.setUp.
  • 在调用startService(Intent) 或bindService(Intent) 之后,ServiceTestCase才会调用Service的onCreate 方法,从而使你有机会在Service启动之前对测试环境做些调整。
  • 当你的测试方法调用startService(Intent) 或bindService(Intent) 之后,ServiceTestCase 调用Service 的onCreate 方法,然后再调用Service相应的 startService(Intent)或 service 的bindService(Intent, ServiceConnection, int)方法。并保存用于tracking 和支持Lifecycle 对应的值。
  • 每个测试方法结束后,调用tearDown 方法,这个方法stop 并destroy 被测试的service. 如果你需要重载tearDown, 注意先调用super.tearDown.

Dependency Injection 每个Service都依赖于运行它的Context 对象和Application 对象,ServiceTestCase 测试框架允许你注入这些对象(修改过,Mocked等)以实现真正的单元测试.

LocalServiceTest 的代码如下:

public class LocalServiceTest extends ServiceTestCase<LocalService> { public LocalServiceTest() { super(LocalService.class); } @Override protected void setUp() throws Exception { super.setUp(); } @SmallTest public void testPreconditions() { } /** * Test basic startup/shutdown of Service */ @SmallTest public void testStartable() { Intent startIntent = new Intent(); startIntent.setClass(getContext(), LocalService.class); startService(startIntent); } /** * Test binding to service */ @MediumTest public void testBindable() { Intent startIntent = new Intent(); startIntent.setClass(getContext(), LocalService.class); IBinder service = bindService(startIntent); }}

testStartable 测试对应的Service能否正常启动。

testBindable 测试对应的Service能否绑定成功



Android测试教程(13):TestCase示例

Published on 2011 年 09 月 01 日

Android 测试框架是基于JUnit的,因此对一些和平台关系不大的类,可以直接使用JUnit中的TestCase来测试。

MorseCodeConverterTest 用来测试MorseCodeConverter类,MorseCodeConverter的实现和Android平台联系不大,因此可以直接使用TestCase作为基类。

TestCase 由Assert 类派生而来,Assert 提供了大量的Assert方法,用来比较期望值和实际值。

本例代码如下:

public class MorseCodeConverterTest extends TestCase { @SmallTest public void testCharacterS() throws Exception { long[] expectedBeeps = { MorseCodeConverter.DOT, MorseCodeConverter.DOT, MorseCodeConverter.DOT, MorseCodeConverter.DOT, MorseCodeConverter.DOT}; long[] beeps = MorseCodeConverter.pattern('s'); assertArraysEqual(expectedBeeps, beeps); } private void assertArraysEqual(long[] expected, long[] actual) { assertEquals("Unexpected array length.", expected.length, actual.length); for (int i = 0; i < expected.length; i++) { long expectedLong = expected[i]; long actualLong = actual[i]; assertEquals("Unexpected long at index: " + i, expectedLong, actualLong); } }}

为一个基本的JUnit Testcase 测试,使用assertEquals 来测试期望值和实际值。


Android测试教程(14):ActivityInstrumentationTestCase2示例

Published on 2011 年 09 月 02 日

ActivityInstrumentationTestCase2 用来测试单个的Activity,被测试的Activity可以使用InstrumentationTestCase.launchActivity 来启动,然后你能够直接操作被测试的Activity。

ActivityInstrumentationTestCase2 也支持:

  • 可以在UI线程中运行测试方法.
  • 可以注入Intent对象到被测试的Activity中

ActivityInstrumentationTestCase2 取代之前的ActivityInstrumentationTestCase ,新的测试应该使用ActivityInstrumentationTestCase2作为基类。

Focus2ActivityTest 的代码如下,用于测试Android ApiDemos示例解析(116):Views->Focus->2. Horizontal

public class Focus2ActivityTest extends ActivityInstrumentationTestCase2<Focus2> { private Button mLeftButton; private Button mCenterButton; private Button mRightButton; public Focus2ActivityTest() { super("com.example.android.apis", Focus2.class); } @Override protected void setUp() throws Exception { super.setUp(); final Focus2 a = getActivity(); mLeftButton = (Button) a.findViewById(R.id.leftButton); mCenterButton = (Button) a.findViewById(R.id.centerButton); mRightButton = (Button) a.findViewById(R.id.rightButton); } @MediumTest public void testPreconditions() { assertTrue("center button should be right of left button", mLeftButton.getRight() < mCenterButton.getLeft()); assertTrue("right button should be right of center button", mCenterButton.getRight() < mRightButton.getLeft()); assertTrue("left button should be focused", mLeftButton.isFocused()); } @MediumTest public void testGoingRightFromLeftButtonJumpsOverCenterToRight() { sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT); assertTrue("right button should be focused", mRightButton.isFocused()); } @MediumTest public void testGoingLeftFromRightButtonGoesToCenter()  { getActivity().runOnUiThread(new Runnable() { public void run() { mRightButton.requestFocus(); } }); // wait for the request to go through getInstrumentation().waitForIdleSync(); assertTrue(mRightButton.isFocused()); sendKeys(KeyEvent.KEYCODE_DPAD_LEFT); assertTrue("center button should be focused", mCenterButton.isFocused()); }}

setUp 中初始化mLeftButton,mCenterButton和mRightButton,调用每个测试方法之前,setUp 都会被调用。

testPreconditions 通常为第一个测试方法,用来检测后续的测试环境是否符合条件。

testGoingRightFromLeftButtonJumpsOverCenterToRight 中调用sendKeys 可以模拟按键消息。

testGoingLeftFromRightButtonGoesToCenter 中 ,使用runOnUiThread 来为mRightButton 请求focus ,使用runOnUiThread 的原因是因为本测试方法不在UI线程中运行。  getInstrumentation 可以取得Instrumentation对象,有了Instrumentation 对象就可以对Activity进行大部分的操作,waitForIdleSync() 等待application 回到idle 状态,之后就可以检测mRightButton 是否获得了焦点。


Android测试教程(15):AndroidTestCase示例

Published on 2011 年 09 月 03 日

AndroidTestCase 为一Android平台下通用的测试类,它支持所有JUnit的Assert方法和标准的setUp 和tearDown 方法。如果你的测试需要访问应用的资源或者测试方法依赖于Context,可以使用AndroidTestCase 作为基类。

它的类继承关系如下图所示:

Focus2AndroidTest 测试也是Android ApiDemos示例解析(116):Views->Focus->2. Horizontal

但测试的侧重点不一样,Focus2AndroidTest 测试的内容无需启动Activity,而是测试R.layout.focus_2 的布局(资源)中Focus 的顺序是否符合预先设计(可以看作是Activity的一些静态性能),可以通过FocusFinder的方法来测试Focus的一些静态属性,它的代码如下:

public class Focus2AndroidTest extends AndroidTestCase { private FocusFinder mFocusFinder; private ViewGroup mRoot; private Button mLeftButton; private Button mCenterButton; private Button mRightButton; @Override protected void setUp() throws Exception { super.setUp(); mFocusFinder = FocusFinder.getInstance(); // inflate the layout final Context context = getContext(); final LayoutInflater inflater = LayoutInflater.from(context); mRoot = (ViewGroup) inflater.inflate(R.layout.focus_2, null); // manually measure it, and lay it out mRoot.measure(500, 500); mRoot.layout(0, 0, 500, 500); mLeftButton = (Button) mRoot.findViewById(R.id.leftButton); mCenterButton = (Button) mRoot.findViewById(R.id.centerButton); mRightButton = (Button) mRoot.findViewById(R.id.rightButton); } @SmallTest public void testPreconditions() { assertNotNull(mLeftButton); assertTrue("center button should be right of left button", mLeftButton.getRight() < mCenterButton.getLeft()); assertTrue("right button should be right of center button", mCenterButton.getRight() < mRightButton.getLeft()); } @SmallTest public void testGoingRightFromLeftButtonJumpsOverCenterToRight() { assertEquals("right should be next focus from left", mRightButton, mFocusFinder.findNextFocus(mRoot, mLeftButton, View.FOCUS_RIGHT)); } @SmallTest public void testGoingLeftFromRightButtonGoesToCenter() { assertEquals("center should be next focus from right", mCenterButton, mFocusFinder.findNextFocus(mRoot, mRightButton, View.FOCUS_LEFT)); }}

testGoingRightFromLeftButtonJumpsOverCenterToRight 和 testGoingLeftFromRightButtonGoesToCenter

通过mFocusFinder 的 findNextFocus 来测试 mLeftButton,mRightButton 的下个可以获取焦点的控件是否符合事先的设计。



Android测试教程(16):monkeyrunner简介

Published on 2011 年 09 月 04 日

如果你需要实现自动测试,Android的monkeyrunner 工具可以帮助你实现自动测试,它提供了一组API可以用来控制Android设备或模拟器,使用monkeyrunner,你可以编写Python 程序来安装Android应用或是测试包,运行应用或测试,发送按键消息,并可以截屏,然后保存在计算机中。monkeyrunner 主要目的是用来在应用程序或框架层次来测试应用程序或运行单元测试包,但你也可以用作其它目的。

monkeyrunner 工具包不同于UI/Application Exerciser Monkey(也称为Money),money 通过adb shell 来运行,可以模拟“猴子”随机按键或是发送系统消息给指定的应用来实现Stress 测试。

monkeyrunner API 主要通过下面三个包:

  • MonkeyRunner: 主要提供了monkeyrunner 应用的辅助方法以及,用来链接设备或是模拟器的方法,并提供UI支持等。
  • MonkeyDevice: 代表一个设备或是模拟器,提供安装,卸载应用的方法,启动一个Activity,发送按键或是Touch 事件等。
  • MonkeyImage: 代表一个截屏图像,可以截取不同格式的图像,比较两个MonkeyImage图像,保存图像等。

下面为一个 Python 写的monkeyrunner 应用, 因为涉及到Python 语言,这里不详细说明了

# Imports the monkeyrunner modules used by this programfrom com.android.monkeyrunner import MonkeyRunner, MonkeyDevice# Connects to the current device, returning a MonkeyDevice objectdevice = MonkeyRunner.waitForConnection()# Installs the Android package. Notice that this method returns a boolean,# so you can test to see if the installation worked.device.installPackage('myproject/bin/MyApplication.apk')# sets a variable with the package's internal namepackage = 'com.example.android.myapplication'# sets a variable with the name of an Activity in the packageactivity = 'com.example.android.myapplication.MainActivity'# sets the name of the component to startrunComponent = package + '/' + activity# Runs the componentdevice.startActivity(component=runComponent)# Presses the Menu buttondevice.press('KEYCODE_MENU','DOWN_AND_UP')# Takes a screenshotresult = device.takeSnapshot()# Writes the screenshot to a fileresult.writeToFile('myproject/shot1.png','png')

详细的API说明请参考Android文档 ,如果你需要实现自动测试,编写测试代码,可以使用Python通过monkeyrunner API来实现。


Android测试教程(17):Monkey 命令行工具

Published on 2011 年 09 月 05 日

写完应用之后,作完单元测试和功能测试,有必要对应用的抗打击能力做个测试,最好的方法是雇个“猴子”在测试,猴子可以胡乱瞎按键,在这种情况下,你的应用是否还能正常工作呢?

Android 测试包中提供了一个Monkey工具,就提供了“猴子”功能,不过比真”猴子“还要智能一些,你还可以指挥这个猴子, 比如按键的比例,触发某个事件的频率等等。

一个简单的用法,比如你的应用程序的包名为:com.pstreets.navigator

可以使用  adb shell monkey -p com.pstreets.navigator -v 500

使用缺省的配置 向应用发送500 个随机事件(包括按键,touch事件,系统事件等),该命令会首先启动对应的Activity,然后向该应用发送随机事件:

Monkey工具的详细说明如下:

它是一个命令行工具 ,可以运行在模拟器里或实际设备中。它向系统发送伪随机的用户事件流,实现对正在开发的应用程序进行压力测试。Monkey包括许多选项,它们大致分为四大类:

· 基本配置 选项,如设置尝试的事件数量。
· 运行约束选项,如设置只对单独的一个包进行测试。
· 事件类型 和频率。
· 调试选项。

在Monkey运行的时候,它生成事件,并把它们发给系统。同时,Monkey还对测试中的系统进行监测,对下列三种情况进行特殊处理:
· 如果限定了Monkey运行在一个或几个特定的包上,那么它会监测试图转到其它包的操作,并对其进行阻止。
· 如果应用程序崩溃或接收到任何失控异常 ,Monkey将停止并报错。
· 如果应用程序产生了应用程序不响应(application not responding)的错误,Monkey将会停止并报错。
按照选定的不同级别的反馈信息,在Monkey中还可以看到其执行过程报告和生成的事件。
Monkey基本用法

可以通过开发机器上的命令行或脚本来启动Monkey。由于Monkey运行在模拟器/设备环境中,所以必须用其环境中的shell来进行启动。可以通过在每条命令前加上adb shell来达到目的,也可以进入Shell后直接输入Monkey命令。基本语法如下:
$ adb shell monkey [options]
如果不指定options,Monkey将以无反馈模式启动,并把事件任意发送到安装 在目标环境中的全部包。下面是一个更为典型的命令行示例,它启动指定的应用程序,并向其发送500个伪随机事件:
$ adb shell monkey -p your.package.name -v 500
–v
命令行的每一个 -v 将增加反馈信息的级别。 Level 0( 缺省值 ) 除启动提示、测试完成和最终结果之外,提供较少信息。 Level 1 提供较为详细的测试信息,如逐个发送到 Activity 的事件。 Level 2 提供更加详细的设置信息,如测试中被选中的或未被选中的 Activity 。
事件
-s <seed>
伪随机数生成器的 seed 值。如果用相同的 seed 值再次运行 Monkey ,它将生成相同的事件序列。
–throttle <milliseconds>
在事件之间插入固定延迟。通过这个选项可以减缓 Monkey 的执行速度。如果不指定该选项, Monkey 将不会被延迟,事件将尽可能快地被产成。
–pct-touch <percent>
调整触摸事件的百分比 ( 触摸事件是一个 down-up 事件,它发生在屏幕上的某单一位置 ) 。
–pct-motion <percent>
调整动作事件的百分比 ( 动作事件由屏幕上某处的一个 down 事件、一系列 的伪随机事件和一个 up 事件组成 ) 。
–pct-trackball <percent>
调整轨迹事件的百分比 ( 轨迹事件由一个或几个随机的移动组成,有时还伴随有点击 ) 。
–pct-nav <percent>
调整“基本”导航事件的百分比 ( 导航事件由来自方向输入设备的 up/down/left/right 组成 ) 。
–pct-majornav <percent>
调整“主要”导航事件的百分比 ( 这些导航事件通常引发图形界面中的动作,如: 5-way 键盘的中间按键、回退按键、菜单按键 )
–pct-syskeys <percent>
调整“系统”按键事件的百分比 ( 这些按键通常被保留,由系统使用,如 Home 、 Back 、 Start Call 、 End Call 及音量控制键 ) 。
–pct-appswitch <percent>
调整启动 Activity 的百分比。在随机间隔里, Monkey 将执行一个 startActivity () 调用,作为最大程度覆盖包中全部 Activity 的一种方法。
–pct-anyevent <percent>
调整其它类型事件的百分比。它包罗了所有其它类型的事件,如:按键、其它不常用的设备按钮、等等。
约束限制
-p <allowed-package-name>
如果用此参数指定了一个或几个包, Monkey 将只允许系统启动这些包里的 Activity 。如果你的应用程序还需要访问其它包里的 Activity( 如选择取一个联系人 ) ,那些包也需要在此同时指定。如果不指定任何包, Monkey 将允许系统启动全部包里的 Activity 。要指定多个包,需要使用多个 -p 选项,每个 -p 选项只能用于一个包。
-c <main-category>
如果用此参数指定了一个或几个类别, Monkey 将只允许系统启动被这些类别中的某个类别列出的 Activity 。如果不指定任何类别, Monkey 将选择下列类别中列出的 Activity : Intent.CATEGORY_LAUNCHER 或 Intent.CATEGORY_MONKEY 。要指定多个类别,需要使用多个 -c 选项,每个 -c 选项只能用于一个类别。
调试
–dbg-no-events
设置此选项, Monkey 将执行初始启动,进入到一个测试 Activity ,然后不会再进一步生成事件。为了得到最佳结果,把它与 -v 、一个或几个包约束、以及一个保持 Monkey 运行 30 秒或更长时间的非零值联合起来,从而提供一个环境,可以监视应用程序所调用的包之间的转换。
–hprof
设置此选项,将在 Monkey 事件序列之前和之后立即生成 profiling 报告。这将会在 data/misc 中生成大文件 (~5Mb) ,所以要小心使用它。
–ignore-crashes
通常,当应用程序崩溃或发生任何失控异常时, Monkey 将停止运行。如果设置此选项, Monkey 将继续向系统发送事件,直到计数完成。
–ignore-timeouts
通常,当应用程序发生任何超时错误 ( 如“ Application Not Responding ”对话框 ) 时, Monkey 将停止运行。如果设置此选项, Monkey 将继续向系统发送事件,直到计数完成。
–ignore-security-exceptions
通常,当应用程序发生许可错误 ( 如启动一个需要某些许可的 Activity) 时, Monkey 将停止运行。如果设置了此选项, Monkey 将继续向系统发送事件,直到计数完成。
–kill-process-after-error
通常,当 Monkey 由于一个错误而停止时,出错的应用程序将继续处于运行状态。当设置了此选项时,将会通知系统停止发生错误的进程。注意,正常的 ( 成功的 ) 结束,并没有停止启动的进程,设备只是在结束事件之后,简单地保持在最后的状态。
–monitor-native-crashes
监视并报告 Android 系统中本地代码的崩溃事件。如果设置了 –kill-process-after-error ,系统将停止运行。
–wait-dbg
停止执行中的 Monkey ,直到有调试器和它相连接。



Android测试教程(18):总结

Published on 2011 年 09 月 06 日

前面基本介绍完了Android测试框架,它是以JUnit为基础,添加了针对Android的TestCase扩展,其中Instrumentation类是非常重要的一个类,它可以直接控制Activity的生命周期,测试的内容除应用的功能,单元测试外,也需要针对屏幕切换(横屏于竖屏转换),系统配置变更(如语言等),电池容量变换以及是否依赖于网络,SD卡等外部资源进行测试。

  1. Android测试教程(1):概述
  2. Android测试教程(2):测试基础
  3. Android测试教程(3):测试项目
  4. Android测试教程(4):测试相关API
  5. Android测试教程(5):第一个测试项目HelloWorldTest
  6. Android测试教程(6):测试Activity
  7. Android测试教程(7):测试Content Provider
  8. Android测试教程(8):测试Service
  9. Android测试教程(9):ApplicationTestCase示例
  10. Android测试教程(10):ActivityInstrumentationTestCase2示例(1)
  11. Android测试教程(11):ActivityUnitTestCase示例
  12. Android测试教程(12):ServiceTestCase示例
  13. Android测试教程(13):TestCase示例
  14. Android测试教程(14):ActivityInstrumentationTestCase2示例(2)
  15. Android测试教程(15):AndroidTestCase示例
  16. Android测试教程(16):monkeyrunner简介
  17. Android测试教程(17):Monkey 命令行工具

0 0
原创粉丝点击