Android服务不是由JUnit测试启动的

时间:2012-07-06 11:25:15

标签: android service junit

我有这个测试类来测试远程服务:

public class CoreServiceBasicTest extends ServiceTestCase<CoreService> implements ServiceConnection {

    /** Tag for logging */
    private final static String TAG = CoreServiceBasicTest.class.getName();

    /** Receive incoming messages */
    private final Messenger inMessenger = new Messenger(new IncomingHandler());

    /** Communicate with the service */
    private Messenger outMessenger = null;

    /** Handler of incoming messages from service */
    private static class IncomingHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            Log.d(TAG, "Incoming message");
        }
    }

    /** Constructor for service test */
    public CoreServiceBasicTest() {
        super(CoreService.class);
    }

    /** Start the service */
    @Override
    public void setUp() {

        // Mandatory
        try {
            super.setUp();
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Start the service
        Intent service = new Intent();
        service.setClass(this.getContext(), CoreService.class);
        startService(service);
        Log.d(TAG, "Service started");
    }

    public void onServiceConnected(ComponentName className, IBinder service) {
        outMessenger = new Messenger(service);
        Log.d(TAG, "Service attached");
    }

    public void onServiceDisconnected(ComponentName className) {
        // TODO Auto-generated method stub

    }

    @SmallTest
    public void testBindService() {
        // Bind to the service
        Intent service = new Intent();
        service.setClass(getContext(), CoreService.class);
        boolean isBound = getContext().bindService(service, this, Context.BIND_AUTO_CREATE);
        assertTrue(isBound);
    }
}

问题是setUp()方法中的startService(service)无法正确启动服务。这就是AVD所显示的:

enter image description here

正如您所看到的,该过程已启动但服务未启动。然后在testBindService()assertTrue(isBound)失败。

如果我从Activity中启动服务,则不会发生这种情况:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Start the Core service
    Intent service = new Intent();
    service.setClass(this, CoreService.class);

    if (startService(service) == null) {
        Toast.makeText(this, "Error starting service!", Toast.LENGTH_LONG).show();
        Log.e(TAG, "Error starting service");
    } else {
        Toast.makeText(this, "Service started sucessfully", Toast.LENGTH_LONG).show();
    }

    // Die
    finish();
}

此处服务正确启动,如下所示。

enter image description here

如何启动并绑定到使用Messenger与Android测试项目中的活动进行通信的远程服务?

2 个答案:

答案 0 :(得分:11)

Android Test Project(test.apk)的重点是检测应用程序项目(app.apk)并对与Application Project相关联的Android组件(活动,服务等)进行单元测试,换句话说,单元测试在app.apk中创建和操作的Activity和Service。

您不应该在Test项目下的ServiceTestCase实现中第二次部分编写MessengerService实现(Messenger,IncomingHandler等)。 MessengerService实现只需要在Application项目的CoreService.java文件中编写一次。

ServiceConnection用于Activity和Service之间的相互通信,因为我们在这里使用ServiceTestCase(意味着单元测试服务,与其他组件的通信超出范围,因此不予考虑),我们不需要ServiceConnection实现。 ServiceConnection唯一做的就是初始化一个可靠的Messenger对象,以便我们可以在以后使用,一旦正确创建了服务:

public void onServiceConnected(ComponentName className, IBinder service) {
  // This is what we want, we will call this manually in our TestCase, after calling
  // ServiceTestCase.bindService() and return the IBinder, check out code sample below.
  mService = new Messenger(service);
}

另请注意,在这种情况下,您不需要调用ServiceTestCase.startService(),因为ServiceTestCase.bindService()将正确启动服务(如果尚未启动)并返回我们需要使用的IBinder对象稍后初始化Messenger对象。

假设您在CoreService.java中的IncomingHandler.handleMessage()实例看起来像这样:

... ...

switch (msg.what) {
  case MSG_SAY_HELLO:
    msgReceived = true;
    break;

... ...

测试ServiceTestCase中的发送消息功能:

... ...

IBinder messengerBinder = null;

@Override
public void setUp() throws Exception {
  super.setUp();
  // Bind the service and get a IBinder:
  messengerBinder = bindService(new Intent(this.getContext(), CoreService.class));
  //log service starting
  Log.d(TAG, "Service started and bound");
}

public void testSendMessage() {
  // Use IBinder create your Messenger, exactly what we did in ServiceConnection callback method:
  Messenger messenger = new Messenger(messengerBinder);
  Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
  messenger.send(msg);
  // Do some assert stuff here
  ... ...
}

... ...

如果您想测试Activity和Service之间的通信,那么ServiceTestCase在这种情况下是不合适的。考虑使用ActivityInstrumentationTestCase2测试实际的Activity(绑定到您的CoreService,这使您能够间接测试您的服务功能。

答案 1 :(得分:7)

只看documentation for ServiceTestCase它说测试框架延迟启动服务,直到您的某个测试方法调用ServiceTestCase.startService()ServiceTestCase.bindService()

查看代码,在ServiceTestCase.startService()方法中调用setUp()不在测试方法中。这还没有启动服务。它正在等待您的一种测试方法来调用ServiceTestCase.startService()ServiceTestCase.bindService()

您的测试方法testBindService()未调用ServiceTestCase.bindService(),而是调用Context.bindService()并失败。测试框架仍在等待,这就是服务未启动的原因。

再次查看链接的开发人员文档中的生命周期支持讨论。