2012-07-06 194 views
5

推出Android服务,我有这个测试类测试远程服务:不是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); 
    } 
} 

的问题是,startService(服务)在SETUP()方法不正确启动该服务。这就是AVD显示:

enter image description here

正如你所看到的,过程被启动,但服务没有。然后在testBindService()assertTrue(isBound)失败。

,如果我从活动推出的服务不会出现这种情况:

@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

我怎么可以就结合使用斜挎带从Android测试项目活动通信的远程服务?

+0

请先做这些检查,以便我们确定它的核心问题而不是语法上的第一个 确保您的清单有这个 '<服务机器人:启用=“真正的”机器人:名字= /“CoreService。‘>' 并应用标签之间的嵌套在像这样' <服务机器人:名字=’” /> ' 还要确保所有的项目依赖关系映射正确 还要检查你的coreservice.java是否在同一个包中或作为活动的不同软件包 - 确保您在清单中拥有正确的软件包名称。 – Slartibartfast 2012-07-09 09:40:21

+0

正如我所说:*“这不会发生,如果我从一个活动启动服务”*,所以显然清单是正确的。同样如您所见,没有“服务未找到”错误,但该过程已启动,但没有附加服务?这是我觉得奇怪的。 – m0skit0 2012-07-09 10:39:55

回答

11

Android测试项目(test.apk)的重点在于测试应用程序项目(app.apk)并单元测试与应用程序项目关联的Android组件(活动,服务等)单词,单元测试活动和服务,它是在app.apk中创建和操作的。

您不应该在测试项目下的ServiceTestCase实现中第二次部分编写MessengerService实现(Messenger,IncomingHandler等)。 MessengerService实现只需要在应用程序项目的CoreService.java文件中写入一次即可。

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

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()impelementation是这样的:

... ... 

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测试实际活动(它绑定到您的CoreService,这使您能够间接测试您的服务功能)

+0

是的,这正是我想要做的:测试发送到服务的消息,而不是应用程序<->服务通信。谢谢! – m0skit0 2012-07-10 10:58:46

+0

@ m0skit0,很高兴听到它帮助:) – yorkw 2012-07-10 11:03:05

7

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

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

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

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

+0

问题是我不能调用'ServiceTestCase.bindService()',这对我没用,因为它不需要'ServiceConnection'。 – m0skit0 2012-07-09 21:10:04

+1

测试框架处理所有连接的东西。它管理ServiceConnection。当你调用ServiceTestCase.bindService()时,它会返回一个IBinder,这正是你使用ServiceConnection的原因。无论如何,如果你不能使用这个测试框架进行测试,因为它没有提供你需要的功能或接口,那么你只需编写你自己的测试工具而不使用这个框架。 – 2012-07-09 22:30:19