2014-03-31 175 views
8

我目前正在嘗試使用TDD編寫Android應用程序。我被賦予編寫一個在應用程序中非常重要的服務的任務。Android:單元測試服務

至於這個原因,我試圖寫一個適當的測試服務。 Android準則聲明如下:

主題「測試內容」列出了測試Android組件的一般注意事項。下面是測試服務的一些具體的指導方針:

  • 確保的onCreate()被調用響應Context.startService()或Context.bindService()。同樣,您應該確保調用onDestroy()以響應Context.stopService(),Context.unbindService(),stopSelf()或stopSelfResult()。 測試您的服務是否正確處理來自Context.startService()的多個調用。只有第一次調用會觸發Service.onCreate(),但所有調用都會觸發對Service.onStartCommand()的調用。此外,請記住startService()調用不會嵌套,因此對Context.stopService()或Service.stopSelf()(但不是stopSelf(int))的單個調用將停止服務。您應該測試您的服務在正確的點停止。

  • 測試您的服務實現的任何業務邏輯。業務邏輯包括檢查無效值,財務和算術計算等等。

Source: Service Testing | Android Developers

我還沒有看到這些生命週期方法正確的測試,Context.startService()等多個呼叫我試圖算出這個,但我」目前處於虧損狀態。

我試圖測試與ServiceTestCase類服務:

import java.util.List; 

import CoreManagerService; 

import org.junit.After; 
import org.junit.AfterClass; 
import org.junit.BeforeClass; 
import org.junit.Before; 
import org.junit.Test; 

import android.app.ActivityManager; 
import android.app.ActivityManager.RunningServiceInfo; 
import android.content.Context; 
import android.content.Intent; 
import android.test.ServiceTestCase; 
import android.test.suitebuilder.annotation.SmallTest; 
import android.util.Log; 

/** 
* 
* This test should be executed on an actual device as recommended in the testing fundamentals. 
* http://developer.android.com/tools/testing/testing_android.html#WhatToTest 
* 
* The following page describes tests that should be written for a service. 
* http://developer.android.com/tools/testing/service_testing.html 
* TODO: Write tests that check the proper execution of the service's life cycle. 
* 
*/ 
public class CoreManagerTest extends ServiceTestCase<CoreManagerService> { 

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

    public CoreManagerTest() { 
     super(CoreManagerService.class); 
    } 

    public CoreManagerTest(Class<CoreManagerService> serviceClass) { 
     super(serviceClass); 

     // If not provided, then the ServiceTestCase will create it's own mock 
     // Context. 
     // setContext(); 
     // The same goes for Application. 
     // setApplication(); 

     Log.d(TAG, "Start of the Service test."); 
    } 

    @SmallTest 
    public void testPreConditions() { 
    } 

    @BeforeClass 
    public static void setUpBeforeClass() throws Exception { 
    } 

    @AfterClass 
    public static void tearDownAfterClass() throws Exception { 
    } 

    @Before 
    public void setUp() throws Exception { 
     super.setUp(); 
    } 

    @After 
    public void tearDown() throws Exception { 
     super.tearDown(); 
    } 

    @Test 
    public void testStartingService() { 
     getSystemContext().startService(new Intent(getSystemContext(), CoreManagerService.class)); 

     isServiceRunning(); 
    } 

    private void isServiceRunning() { 
     final ActivityManager activityManager = (ActivityManager)this.getSystemContext() 
       .getSystemService(Context.ACTIVITY_SERVICE); 
     final List<RunningServiceInfo> services = activityManager 
       .getRunningServices(Integer.MAX_VALUE); 

     boolean serviceFound = false; 
     for (RunningServiceInfo runningServiceInfo : services) { 
      if (runningServiceInfo.service.getClassName().equals(
        CoreManagerService.class.toString())) { 
       serviceFound = true; 
      } 
     } 
     assertTrue(serviceFound); 
    } 
} 

我是不是正確處理這個?我應該使用活動測試來測試服務的綁定嗎?

+1

對此有何更新?我一直在尋找類似的答案,但沒有發現任何有用的東西。 – Mira

+0

自從我問這個問題已經有一段時間了,我想我可能會寫一個測試生命週期方法的單元測試。您可以使用Broadcasts(context.sendBroadcast()和broadcastreceiver)將消息從服​​務發送到測試。我可以爲你寫一篇,但是當我有時間的時候,我必須看到。 – Orion

+0

那麼我有一個粘性的遠程服務,它運行另一個線程來做異步任務。測試生命週期會很好,但我真正需要的是測試線程處理程序。我沒有看到太多的例子。我正在考慮爲我的線程創建存根或使用模擬對象,但我不知道如何測試服務或狀態更改中的非生命週期方法。有任何想法嗎? – Mira

回答

5

即使世界的example using JUnit 4

服務:

/** 
* {@link Service} that generates random numbers. 
* <p> 
* A seed for the random number generator can be set via the {@link Intent} passed to 
* {@link #onBind(Intent)}. 
*/ 
public class LocalService extends Service { 
    // Used as a key for the Intent. 
    public static final String SEED_KEY = "SEED_KEY"; 

    // Binder given to clients 
    private final IBinder mBinder = new LocalBinder(); 

    // Random number generator 
    private Random mGenerator = new Random(); 

    private long mSeed; 

    @Override 
    public IBinder onBind(Intent intent) { 
     // If the Intent comes with a seed for the number generator, apply it. 
     if (intent.hasExtra(SEED_KEY)) { 
      mSeed = intent.getLongExtra(SEED_KEY, 0); 
      mGenerator.setSeed(mSeed); 
     } 
     return mBinder; 
    } 

    public class LocalBinder extends Binder { 

     public LocalService getService() { 
      // Return this instance of LocalService so clients can call public methods. 
      return LocalService.this; 
     } 
    } 

    /** 
    * Returns a random integer in [0, 100). 
    */ 
    public int getRandomInt() { 
     return mGenerator.nextInt(100); 
    } 
} 

測試:

public class LocalServiceTest { 
    @Rule 
    public final ServiceTestRule mServiceRule = new ServiceTestRule(); 

    @Test 
    public void testWithBoundService() throws TimeoutException { 
     // Create the service Intent. 
     Intent serviceIntent = 
       new Intent(InstrumentationRegistry.getTargetContext(), LocalService.class); 

     // Data can be passed to the service via the Intent. 
     serviceIntent.putExtra(LocalService.SEED_KEY, 42L); 

     // Bind the service and grab a reference to the binder. 
     IBinder binder = mServiceRule.bindService(serviceIntent); 

     // Get the reference to the service, or you can call public methods on the binder directly. 
     LocalService service = ((LocalService.LocalBinder) binder).getService(); 

     // Verify that the service is working correctly. 
     assertThat(service.getRandomInt(), is(any(Integer.class))); 
    } 
} 
+1

以上鍊接無效 – w3bMak3r

+0

@ w3bMak3r固定 – Caipivara

+0

如果您不使用可綁定服務,會發生什麼情況? –