2.3. The Testing API(测试API)
Android的测试API是基于JUnitAPI和扩展的instrumentation 框架以及特定的Android测试类。
2.3.1. Junit
你可以使用TestCase类来做单元测试而不调用 Android的API。TestCase
是
AndroidTestCase
类的父类,你可以用它来做
Android
依赖的对象。除了提供的
JUnit
框架,
AndroidTestCase
提供了
Android
特殊的建立,销毁以及帮助方法。
你使用
Assert 类来展示测试的结果,assert比较值方法可以通过你期待的测试结果和实际的结果做比较并且抛出异常来判断比较是否失败。Android还提供了一个类的断言,使得可以比较的类型更多,另一类的断言用于进行UI测试。更多的详细描述在 Assertion classes
想要了解更多的东西关于JUnit,你可以在 junit.org 的主页上阅读到更多的文档。值得注意的是Android的测试API支持的是JUnit3的代码风格而不是JUnit4.你必须使用Android的测试运行器工具InstrumentationTestRunner来运行你的程序。这个测试类的描述文档在Running Tests
2.3.2.
Instrumentation
Android的instrument是一系列的控制方法以及Android 系统自己设置的“钩子”。这些钩子能够控制独立的Android组件正常生命周期。他们也能控制怎么样加载Android运用程序。
正常情况下,Android的组件运行测生命周期是由系统决定的。例如,一个Activity对象的生命周期开始是由intent激活的。这个对象首先使用onCreat()调用,之后跟随着onResume().当用户开始另一个应用程序的时候会调用onPause()方法。如果这个Activity调用了finish()方法,则onDestroy()方法将会被调用。Android的运用框架层并没有提供这些方法来直接的调用来调用这些函数,但是你可以使用instrumentation来实现这些功能。
同样的,系统运行所有的组件在同一个进程。当然,你可以允许一些组件,像contentproviders 可以运行在不同的进程中,但是你不能强制一个应用程序强制和另一个已经在运行的应用程序在同一个进程当中运行。
使用Android的instrumentation,尽管你可以在你的测试代码中调用你的这些方法。同样可以让你运行一步一步按照生命周期来运行组件,就好像你在调试组件一样。
下面的这段代码演示了怎么保存和恢复Activity的状态:
// 在测试环境下启动Activity
mActivity = getActivity();
// 得到这个Activity中的主要UI句柄,一个Spinner
mSpinner = (Spinner)mActivity.findViewById(com.android.example.spinner.R.id.Spinner01);
//获取Spinner的位置
mActivity.setSpinnerPosition(TEST_STATE_DESTROY_POSITION);
// Stop theactivity - The onDestroy() method should save the state of the Spinner 停止activity,调用onDestroy方法保存Spinner的状态
mActivity.finish();
// Re-start theActivity - the onResume() method should restore the state of the Spinner重新启动Activity,onResume()方法应该保存Spinner
mActivity = getActivity();
// Get theSpinner's current position 获取Spinner的位置
int currentPosition = mActivity.getSpinnerPosition();
// Assert thatthe current position is the same as the starting position判断当前的位置和启动之前的位置是不是一样的
assertEquals(TEST_STATE_DESTROY_POSITION, currentPosition);
这里关键的方法就是使用 getActivity(),它是instrumentation中的API的一部分。直到测试开始的时候才会调用这个方法。你可以提前设置测试的固件,这样使得它能调用启动时候的Activity.
同时,instrumentation能够加载测试包和应用程序到相同的进程。因为它们测试组件和测试程序在同一个进程,测试能够调用组件的方法,并且能够修改检测组件的字段。
Test case classes
Android提供了几个测试用例类来扩展测试用例和断言针对Android中的安装,销毁,和辅助方法。
AndroidTestCase
一个十分有用的测试类,特别是你开始进行Android的测试。它继承自 TestCase 和Assert。它可以提供JUnit标准的setUp()方法和tearDown()方法,这对JUnit断言方法是一样的。除此之外,它提供的方法可以测试权限,一种防止内存泄露的类额度引用。
Component-specific test cases
在Android测试框架中一个主要的特征就是组件的测试类。这里描述了特定组件的测试方法和固件安装以及销毁组件的生命周期的控制方法。他们同时也提供方法来建立模拟相应的对象。他们还提供了设置模拟对象的方法,这些测试主题:
Android没有提供单独的测试类给BroadcastReceiver。测试BroadcastReceiver通过测试Intent对象的组件,确认BroadcastReceiver是不是能够正确响应正确。
ApplicationTestCase
你使用 ApplicationTestCase
测试类来启动或者是销毁APP。这些对象维护全局状态信息,适用于一个应用程序的所有组件。这些测试用例能够确认<application>元素设置的正确性。注意,但是这个组件不允许你控制测试组件的应用程序包。
InstrumentationTestCase
如果你想使用instrumentation方法在测试用例类中,你必须使用InstrumentationTestCase或者其子类。Activity测试扩展了其父类的一些功能在判断Activity测试时。
Assertion classes
因为Android的测试用例类继承自JUnit,你可以使用断言方法来展示出测试的结果。一个断言的方法通过比较真实方法会和测试希望得到的值来抛出一个AssertionException如果对比测试失败的话。使用断言比日志记录更加方便,并且提供更好的测试性能。
除了JUnit Assert
类方法,测试API同样提供了 MoreAsserts
和 ViewAsserts
类:
MoreAsserts
它包含了很多强大的断言例如: assertContainsRegex(String, String)
能够定期的展示出匹配
ViewAsserts
包含了很多有用的关于Views的断言。例如它包含了 assertHasScreenCoordinates(View, View, int, int)
如果View在屏幕上有一个很好的X和Y的坐标,它能够简单的测试几何形状和进行比对测试。
Mock object classes
为了方便依赖注入测试,Android提供了类能够产生模拟系统的对象例如 Context
类, ContentProvider
对象, ContentResolver
对象, and Service
对象。一些测试同样也提供了模拟Intent的对象。你使用这些模拟对象可是实现系统的某一部分的独立测试或者是方便注入测试。这些类都在 android.test
和android.test.mock测试。Mock对象是一个独立的测试和正在运行的系统是完全隔离的或者是覆盖了正常的运行操作。例如,一个MockContentResolver
代替了正常的resolver框架使用自己的本地框架,能够独立于系统运行。
MockContentResolver 同样也使用 notifyChange(Uri, ContentObserver, boolean)
方法来观察对象的外部环境是不是非偶然触发的。
模拟类也有利于实现依附性注入通过提供一个非功能性的正常对象的子类来重新定义。例如, MockResources
提供一个子类 Resources
所有的方法 在被调用的时候都会抛出一个异常,重写的方法必须是提供信息的方法。
下面是在Android中可以使用的mock类:
MockApplication, MockContext, MockContentProvider, MockCursor, MockDialogInterface, MockPackageManager, 以及MockResources提供一个简单并且有用的模拟策略。他们是独立于相关系统的版本的类,并且所有的这些方法在调用的时候都会抛出 UnsupportedOperationException
当被调用的时候。为了使用他们,你重载的方法必须提供模拟依附。
注意:MockContentProvider
和 MockCursor
中API的等级为8.
Resolver mock objects
MockContentResolver
提供了 独立的测试contentprovider框架通过覆盖正常的系统的resolver框架。不是在系统中找一个contentprovider给它付一个本地字符串,MockContentResolver使用他自己的内部表格。你必须明确的使用这个表格通过 addProvider(String, ContentProvider)
.
Contexts for testing 上下文测试
Android提供了两个有用的Context测试类:
- l
IsolatedContext
提供一个独立的Context
, 文件,目录以及数据库操作,使用Context来产生一个测试区域。尽管这个功能是有限的,Context有足够的桩代码来回应系统调用。这些类允许你测试应用程序的数据操作,而不影响真是数据在设备上可能存在的装置。 - l RenamingDelegatingContext 提供了一个Context其大部分的功能就是负责存在的Context,但是文件盒数据库的操作是由
IsolatedContext
来单独负责的。这些独立的部分使用一个测试目录并且产生一个特定的文件以及目录的名字。你自己不能控制目录的名字或者自己决定结构。这个对象提供了一种快速的方法来建立独立的区域进行数据操作,保持其他的Context操作的正常性。