2014-03-31 176 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

如果您不使用可绑定服务,会发生什么情况? –