对Service进行测试,首先你得熟悉service的两种生命周期,即onCreate——onBind 和onCreate——onStartCommand。
启动服务的方式分别是startService()和bindService()。
创建测试类需要继承ServiceTestCase这个类,默认初始化会设定mock Context和mock Application,已达到与被测对象的独立,实现单元测试的目的。
需要说明下的是ServiceTestCase.bindService()和Service.bindService()方法的不同之处在于:1、入参不一样,第一个只需要intent就行了。 2、返回值不一样 第一个返回IBinder对象
与ActivityInstrumentationTestcase一样,需要复写setUp与tearDown以达到初始化与事后处理的目的,若要在里面实现,需在super后编写实现语句。
默认情况下,ServiceTestCase会运行testAndroidTestCaseSetupProperly()方法来确定测试类正确地搭建好了Context。
那么对于Service进行测试到底要测什么呢?在SDK中所提到的主要有以下几个方面:
1.调用Context.startService()或者Context.bindService()后要确定onCreate()方法被正确地调用;同样,当调用Context.stopService(), Context.unbindService(), stopSelf()或者 stopSelfResult()等方法时要确定onDestroy()方法被正确地调用。
2.服务能够正确地处理Context.startService()的多次调用,只有第一次调用才会触发Service.onCreate()方法,但是每次都会调用Service.onStartCommand()方法。还要注意的是startService()不会嵌套调用,因此对Context.stopService()或者 Service.stopSelf() ( stopSelf(int)不再此列)的一次调用就应该能够终止服务。
3.测试服务在实现上的逻辑正确性。
下面就以一个示例代码来看:
public class IRemoteServiceTest extends ServiceTestCase { private final static String IRemoteService = "com.noah.remote.service.IRemoteService"; private static Class iRemote; private IRemoteCommand iCommand; static{ try { iRemote = Class.forName(IRemoteService); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public IRemoteServiceTest() { super(iRemote); // TODO Auto-generated constructor stub } @Override protected void setUp() throws Exception { super.setUp(); } @Override protected void tearDown() throws Exception { super.tearDown(); } public void testOnCreate(){ Intent in = new Intent(); in.setClassName(getContext(), IRemoteService); IBinder binder = bindService(in); if(binder.isBinderAlive()){ iCommand = IRemoteCommand.Stub.asInterface(binder); } } }
若没有被测代码的源代码,但知道被测service的包名,可以用上面的方式构造一个测试类。
在testOnCreate测试方法中绑定这个service,最后拿到的iCommand对象就是我们的被测对象,接下来就可以对这个对象里面的api进行调用并检查是否运行正确。
startService的方式一样,在启动service后,通过getService()方法调用拿到这个service对象,再进行接下来的测试。