2012-07-06 165 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