你的位置:首页 > Java教程

[Java教程]Android测试基础

android测试框架(Android Testing Framework)是开发环境的一部分,它提供了架构和强大的工具帮助你从单元到框架测试应用的各个方面。


关键特性:

  • 基于 JUnit,可直接使用JUnit测试一些与Android AP不相关的类,或使用 Android的JUint 扩展来测试 Android 组件。如果你刚开始接触 Android 测试,可以先从 AndroidTestCase开始写一些通用目的的测试用例,然后再写较复杂的测试用例。
  • Android JUint扩展提供了对 Android 特定组件的测试类,提供了创建mock对象辅助方法及控制组件生命周期的方法。
  • Test suite包含在测试包中,操作和主程序包类似。
  • Eclipse ADT包含了创建和测试的SDK 工具,并可通过命令行在其它IDE使用。这些工具从被测试的应用读取信息并自动创建测试包的build 文件,mainfest文件和文件目录结构。
  • SDK 提供了moneyrunner(用python书写脚本)及Monkey(发送伪随机事件的UI压力测试工具)。


本文档描述了android测试框架的基础,包含测试结构、开发测试的API以及启动测试和查看测试结果的工具。本文假设你有android应用编程以及JUnit测试的基础。测试框架图如下:

测试结构

android的构建和测试工具假设测试项目都组织成类似测试、测试类、测试包和测试项目的标准结构。android测试基于JUnit。通常JUnit测试就是测试“待测试应用”的方法。测试方法构成的类为test cases (或者test suites)。JUnit中编译测试源文件到class文件中。类似地android中用android的编译工具编译测试包中的测试源文件为class文件。在JUnit 中test runner来执行测试类。在android中使用测试工具加载测试包和被测应用,然后调用android的test runner。

 

测试项目

测试项目就是一个目录或者eclipse 工程,可在其中新建源代码、manifest文件以及测试包的其它文件。建议使用Android tool创建测试项目:

  • 自动配置InstrumentationTestRunner为测试执行器。必须使用InstrumentationTestRunner或者其子类来执行JUnit测试。
  • 为测试包取合适的名字。如果被测应用为com.mydomain.myapp,Android tool自动命名测试包名为com.mydomain.myapp.test。
  • 自动创建合适的构建文件、manifest 文件以及目录结构。


推荐的目录结构:

 MyProject/   AndroidManifest.     ... (resources for main application)   src/     ... (source code for main application) ...   tests/     AndroidManifest.       ... (resources for tests)     src/       ... (source code for tests)

注:这个在实际操作中往往根据IDE而不同,请以具体IDE的实例为准。 


测试API

Android测试API基于JUnit API 并扩展了instrumentation框架和Android特有的测试类。

JUnit


使用JUnit的TestCase类可对未使用android API的类进行单元测试。TestCase也是AndroidTestCase(测试依赖于android的对象)的基类。AndroidTestCase还提供了android特有的 setup、teardown以及其它帮助方法。JUnit的Assert类可以显示结果,assert方法比较期望值与实际结果,在比较失败时抛出异常。android同样提供了扩展了比较类型的断言类,以及用来测试UI的断言类。注意android测试API支持JUnit 3的代码风格,不支持JUnit 4。

Instrumentation

android instrumentation是android系统中一系列控制方法或钩子(hooks)。这些钩子可以的正常生命周期内独立地控制组件。它同样可以控制android如何加载应用。通常android组件会按照系统指定的生命周期来运行,例如Activity的生命周期开始于它被Intent激活,其onCreate()方法会被调用,接下来是onResume(),当用户启动另外一个应用,onPause()方法会调用 ,如果Activity调用finish()方法,它的onDestroy()方法也会被调用。android framework API不会提供方法让你在代码中直接调用这些回调方法,但是用instrumentation可以。系统把应用中的所有组件运行在同一个进程中,你可以让一些组件,比如content provider,运行在单独的进程中。但是无法强制应用与另外其他正在运行的应用运行在同一个进程中。通过android imstrumentation,你可以在测试代码中直接调用回调方法,让你渗透组件的生命周期,就像调试。下面的测试代码演示了如何用instrumentation来测试Activity保存和恢复状态:   

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


代码中使用的关键方法是getActivity(),它属于android instrumentation API。调用该方法才会启动Activity。你可以提前配置测试所需的环境(test fixture)。

Instrumentation可以加载测试包和被测试应用到同一个进程,这样测试代码可以调用应用组件的方法,修改和检查组件中的域。

Test case 类


android提供了几个继承自TestCase和Assert的test case 类,它们都有andorid 特有的setup、teardown以及其它的辅助方法。


AndroidTestCase


通用的test case类,继承了TestCase和Assert类。它提供了标准的JUnit中的setup()和teardown()方法,同时还有JUnit的Assert方法。另外它也提供了用来测试权限的方法以及通过清除一定的类引用来防止内存泄露的方法。

组件特有的test case

android测试框架的一个重要特点是组件test case类。它们有独特的setup和teardown及控制组件生命周期。同时它们也提供mock方法。1、Activity Testing2、Content Provider Testing3、Service TestingAndroid并没有为 BroadcastReceiver提供单独的test case 类。可以通过测试发送Intent对象给它的组件来测试BroadcastReceiver,检查BroadcastReceiver回复是否正确。

ApplicationTestCase


用ApplicationTestCase测试Application对象的setup和teardown。这些对象维护着应用程序包中所有组件信息的全局状态,该test case 用于验证manifest 文件中的<application>元素是否正确配置。然而记住这个test case无法控制应用包组件的测试。

InstrumentationTestCase

如果想在test case 类中使用 instrumentation 的方法,必须使用InstrumentationTestCase或者它的子类。Activity test case 继承该基类。

Assertion 类

Android test case 类继承自JUnit,可以用断言来显示测试结果。assertion方法将测试返回的真实值和期望值进行比较,如果比较失败它会抛出AssertionException。用Assertion比打印log更方便,有更好的测试性能。除了JUnit的Assert类的方法,测试API同时也提供了MoreAsserts和ViewAsserts类:

  • MoreAsserts包含更多强大的断言,例如进行正则表达式匹配的assertContainsRegex(String, String)。
  • ViewAsserts包含很多关于View的断言,例如它包含用来测试View是否在屏幕的特定的(x, y)位置的assertHasScreenCoordinates(View, View, int, int)方法,这些断言简化了UI中的几何和对准测试。

模拟对象类


为了解决测试过程中的依赖,Android提供了创建模拟系统对象的类,比如Context对象、ContentProvider对象、ContentResolver对象以及Service对象。有些test case能模拟的Intent对象。通过使用这些模拟对象,你可以将测试与系统的其余部分隔离开,同时也满足了测试中的依赖,这些类都在包android.test和android.test.mock中。模拟对象通过打桩或者重载正常操作来实现将测试与正在运行的系统隔离。例如MockContentResolver对象用它自有的与系统隔离的本地框架来代替通常的resolver框架。同时MockContentResolver不使用notifyChange(Uri, ContentObserver, boolean)方法,这样测试环境以外的observer对象不会被意外触发。模拟对象类也通过提供正常类的子类来满足测试的依赖,该子类除了你覆写的方法外其它都是不起作用的。例如,MockResources对象是Resources类的子类,每个方法在调用时都会抛出异常。要使用它,你只需要重载需要的方法。下面是Android中可用的模拟对象类:

基本的模拟对象类

MockApplication、MockContext、MockContentProvider、MockCursor,、MockDialogInterface、MockPackageManager和MockResources提供了简单有用的模拟策略(打桩),在调用时都会抛出UnsupportedOperationException异常。使用它,你只需要重载需要的方法。注意:MockContentProvider和MockCursor是API Level 8 中新加入。

Resolver 模拟对象

MockContentResolver通过屏蔽系统正常的resolver框架来为content provider 提供隔离的测试。MockContentResolver不是在系统中查找提供authority的content provider,而是使用自己的内部表,你必须显式地用addProvider(String, ContentProvider)方法将provider添加到表中。通过这个特性可以将模拟的content provider与authority关联,新建provider对象但使用测试数据,你甚至可以设置provider的authority为null。实际上MockContentResolver对象将你的测试与包含真实数据的provider隔离。你可以控制provider的功能并防止测试影响真实数据。


Context测试  


android提供了两个Context类来提供测试:

  • IsolatedContext类提供隔离的Context,使用该Context的文件、目录和数据库操作都会在测试区域。尽管功能有限,但足以应对系统调用,允许在不影响当前设备上的真实数据的前提下测试应用的数据操作。
  • RenamingDelegatingContext的Context的大部分功能都由现有的Context来处理,但是文件和数据库操作都由IsolatedContext来处理,隔离的部分使用一个测试目录,并且创建特殊的文件和目录名,你可以自己控制命名,也可以让constructor自动指定。该类为进行数据操作创建隔离区域提供了快捷办法,同时不会影响Context其它的正常操作。

运行测试

test case由test runner类运行,test runner加载test case类、初始化、运行及清理测试。android test runner必须配置,这样启动应用的系统工具可以控制测试包如何加载test case和被测试应用。一般在manifest文件中设定。InstrumentationTestRunner是android中主要的test runner类,它扩展了JUnit test runner框架并且是已配置,能够执行任何android系统提供的test case 类并且支持所有类型的测试。你可指定测试包的manifest文件的<instrumentation>标签内容为Instrumentation 或其子类。InstrumentationTestRunner的代码在共享库android.test.runner中,所以它通常没有链接到你的代码,必须在<uses-library>标签中指定。通常不需要手动去设定,Eclipse ADT以及android 命令行工具都会自动生成它们并且把它们加到测试包的manifest文件中。注意:如果使用的是InstrumentationTestRunner之外的test runner,必须修改<instrumentation>标签并指向你想使用的类。要运行InstrumentationTestRunner类必须用android 工具调用内部系统类。Eclipse ADT中这些类都会被自动调用,命令行工具执行测试的时用Android Debug Bridge (adb)运行这些类。系统类加载和启动测试包,杀掉被测试应用包正在运行的进程,并且重新加载被测试包的实体,然后它们把控制权交给InstrumentationTestRunner,由它来执行测试包中的每个test case。你也可以通过Eclipse ADT中的setting或者命令行工具中的flag来控制哪些 test case或者方法的运行。既不是系统类也不是InstrumentationTestRunner运行被测试应用,而是test case。它要么调用被测试包中的方法,要么调用它自己的方法以改变被测试包生命周期。应用程序完全由test case 控制,测试开始前由test case来初始化测试环境,关于更多的运行测试,可以参见 Testing from Eclipse with ADT和 Testing from Other IDEs。

查看测试结果

Android 测试框架返回测试结果给启动测试的工具。在eclipse ADT中结果会在新的JUnit视图面板中显示,命令行会在STDOUT中显示。两者都可以看到显示每个test case 名字和你所运行的方法的小结,同时会看到所有失败的断言,其中包含指向产生失败的测试代码所在行的链接。失败的断言同时也会列出期望值和实际值。测试结果根据IDE不同而有不同。


monkey 和 monkeyrunner


SDK提供了两个应用测试工具:

  • UI/Application Exerciser Monkey,通常称为"monkey",向设备发送伪随机事件流(如击键、触控、手势)的命令行工具。你可以通过Android Debug Bridge (adb)来运行它,对应用进行压力测试然后报告遇到的错误。你可以通过每次使用相同的随机数种子来重复步骤。
  • monkeyrunner是一套API,基于Python。该API包含如下功能:连接到设备、安装和卸载软件包、截图、比较图片、运行应用对应的测试应用。通过该API,你可以写出功能强大复杂的测试,通过命令行工具monkeyrunner来运行。

 

处理包名

 

测试环境需要同时处理android应用包名和java包标识符。它们都使用同样的命名格式,但是代表着完全不同的实体。android包名是.apk文件对应的一个独一无二的系统名字,由应用包的manifest文件中<manifest>标签中的"android:package"属性来设定。测试包的名字必须和被测试包的名字不同,通常android工具会用被测试包的名字后加上".test"来作为测试包的名字。测试包也会用包名来定位它所测试的应用,元由测试包的manifest文件中<instrumentation>素的"android:targetPackage"属性设定。


java包标识符对应源文件,包名反映了源文件所在目录,它同时会影响类与成员间彼此的可访问性。android 工具会帮助你设定测试包的名字。根据你的输入,工具会设定测试包的名字以及测试的目标包的名字。只有在被测试应用工程已经存在的情况下这些工具才会起作用。默认情况下,这些工具会将测试类的包标识符设定为与被测试应用的包标示符一致。如果你想暴露被测试包中的一些成员你可能需要做一些修改。如果要修改,只修改java 包标示符,不要修改android 包名,只修改test case 的源文件而不要修改测试包中R.java文件的包名,因为修改它会造成与被测试包中的R.java类冲突。不要将测试包的android包名修改成和它所测试的应用的包名一样,因为这样它们的名字在系统中不再是独一无二的。测试内容What To Test详细地描述了android应用中应该被测试的关键功能以及可能会影响该功能的状况。大部分的单元测试是专门针对你正在测试的andorid组件。Activity Testing、 Content Provider Testing和 Service Testing中都有一章节列出“需要测试什么”。尽量在真实的设备上运行这些测试。其次用Android Emulator来加载已经配置好你所希望测试的硬件、屏幕、版本的android vitual device。

 

参考资料

http://developer.android.com/intl/zh-cn/tools/testing/testing_android.html

http://www.uml.org.cn/mobiledev/201306074.asp

本文地址:http://www.cnblogs.com/pythontesting/p/4916574.html