Service Testing

Android provides a testing framework for Service objects that can run them in isolation and provides mock objects. The test case class for Service objects is ServiceTestCase. Since the Service class assumes that it is separate from its clients, you can test a Service object without using instrumentation.

This document describes techniques for testing Service objects. If you aren't familiar with the Service class, please read the Services document. If you aren't familiar with Android testing, please read Testing Fundamentals, the introduction to the Android testing and instrumentation framework.

Service Design and Testing

When you design a Service, you should consider how your tests can examine the various states of the Service lifecycle. If the lifecycle methods that start up your Service, such as onCreate() or onStartCommand() do not normally set a global variable to indicate that they were successful, you may want to provide such a variable for testing purposes.

Most other testing is facilitated by the methods in the ServiceTestCase test case class. For example, the getService() method returns a handle to the Service under test, which you can test to confirm that the Service is running even at the end of your tests.

ServiceTestCase

ServiceTestCase extends the JUnit TestCase class with with methods for testing application permissions and for controlling the application and Service under test. It also provides mock application and Context objects that isolate your test from the rest of the system.

ServiceTestCase defers initialization of the test environment until you call ServiceTestCase.startService() or ServiceTestCase.bindService(). This allows you to set up your test environment, particularly your mock objects, before the Service is started.

Notice that the parameters to ServiceTestCase.bindService()are different from those for Service.bindService(). For the ServiceTestCase version, you only provide an Intent. Instead of returning a boolean, ServiceTestCase.bindService() returns an object that subclasses IBinder.

The setUp() method for ServiceTestCase is called before each test. It sets up the test fixture by making a copy of the current system Context before any test methods touch it. You can retrieve this Context by calling getSystemContext(). If you override this method, you must call super.setUp() as the first statement in the override.

The methods setApplication() and setContext(Context) setContext()} allow you to set a mock Context or mock Application (or both) for the Service, before you start it. These mock objects are described in Mock object classes.

By default, ServiceTestCase runs the test method testAndroidTestCaseSetupProperly(), which asserts that the base test case class successfully set up a Context before running.

Mock object classes

ServiceTestCase assumes that you will use a mock Context or mock Application (or both) for the test environment. These objects isolate the test environment from the rest of the system. If you don't provide your own instances of these objects before you start the Service, then ServiceTestCase will create its own internal instances and inject them into the Service. You can override this behavior by creating and injecting your own instances before starting the Service

To inject a mock Application object into the Service under test, first create a subclass of MockApplication. MockApplication is a subclass of Application in which all the methods throw an Exception, so to use it effectively you subclass it and override the methods you need. You then inject it into the Service with the setApplication() method. This mock object allows you to control the application values that the Service sees, and isolates it from the real system. In addition, any hidden dependencies your Service has on its application reveal themselves as exceptions when you run the test.

You inject a mock Context into the Service under test with the setContext() method. The mock Context classes you can use are described in more detail in Testing Fundamentals.

What to Test

The topic What To Test lists general considerations for testing Android components. Here are some specific guidelines for testing a Service:

  • Ensure that the onCreate() is called in response to Context.startService() or Context.bindService(). Similarly, you should ensure that onDestroy() is called in response to Context.stopService(), Context.unbindService(), stopSelf(), or stopSelfResult().
  • Test that your Service correctly handles multiple calls from Context.startService(). Only the first call triggers Service.onCreate(), but all calls trigger a call to Service.onStartCommand().

    In addition, remember that startService() calls don't nest, so a single call to Context.stopService() or Service.stopSelf() (but not stopSelf(int)) will stop the Service. You should test that your Service stops at the correct point.

  • Test any business logic that your Service implements. Business logic includes checking for invalid values, financial and arithmetic calculations, and so forth.
{"cc_re__cc_re__cc_by_2_5": ["schema.org/SiteNavigationElement\">\n        <div class=\"layout-content-col col-9\" style=\"padding-top:4px\">\n          \n            <div class=\"g-plusone\" data-size=\"medium\"></div>\n          \n        </div>\n        \n        <div class=\"paging-links layout-content-col col-4\">\n          \n        </div>\n        \n      </div>\n      \n      \n      \n\n  </div> <!-- end jd-content -->\n\n<div id=\"footer\" class=\"wrap\" >\n        \n\n  <div id=\"copyright\">\n    \n  Except as noted, this content is \n  licensed under <a href=\"http://creativecommons.org/licenses/by/2.5/\">\n  Creative Commons Attribution 2.5</a>. For details and \n  restrictions, see the <a href=\"../../license.html\">Content \n  License</a>.\n  </div>\n\n\n  <div id=\"footerlinks\">\n    \n  <p>\n    <a href=\"../../about/index.html\">About Android</a>&nbsp;&nbsp;|&nbsp;\n    <a href=\"../../legal.html\">Legal</a>&nbsp;&nbsp;|&nbsp;\n    <a href=\"../../support.html\">Support</a>\n  </p>\n  </div>\n\n</div> <!-- end footer -->\n</div><!-- end doc-content -->\n\n</div> <!-- end body-content --> \n\n\n\n\n<!-- Grid - for dev \n<scr"], "copyright__copyright__copyright": ["first call triggers Service.onCreate(), but all calls trigger a call to Service.onStartCommand().\n\n    In addition, remember that startService() calls don't nest, so a single call to Context.stopService() or Service.stopSelf() (but not stopSelf(int)) will stop the Service. You should test that your Service stops at the correct point.\n\n  \u2022 Test any business logic that your Service implements. Business logic includes checking for invalid values, financial and arithmetic calculations, and so forth."]}