1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.test; 18 19 import android.app.Application; 20 import android.app.Service; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.os.IBinder; 24 import android.test.mock.MockApplication; 25 26 import java.util.Random; 27 28 /** 29 * This test case provides a framework in which you can test Service classes in 30 * a controlled environment. It provides basic support for the lifecycle of a 31 * Service, and hooks with which you can inject various dependencies and control 32 * the environment in which your Service is tested. 33 * 34 * <div class="special reference"> 35 * <h3>Developer Guides</h3> 36 * <p>For more information about application testing, read the 37 * <a href="{@docRoot}guide/topics/testing/index.html">Testing</a> developer guide.</p> 38 * </div> 39 * 40 * <p><b>Lifecycle Support.</b> 41 * A Service is accessed with a specific sequence of 42 * calls, as described in the 43 * <a href="http://developer.android.com/guide/topics/fundamentals/services.html">Services</a> 44 * document. In order to support the lifecycle of a Service, 45 * <code>ServiceTestCase</code> enforces this protocol: 46 * 47 * <ul> 48 * <li> 49 * The {@link #setUp()} method is called before each test method. The base implementation 50 * gets the system context. If you override <code>setUp()</code>, you must call 51 * <code>super.setUp()</code> as the first statement in your override. 52 * </li> 53 * <li> 54 * The test case waits to call {@link android.app.Service#onCreate()} until one of your 55 * test methods calls {@link #startService} or {@link #bindService}. This gives you an 56 * opportunity to set up or adjust any additional framework or test logic before you test 57 * the running service. 58 * </li> 59 * <li> 60 * When one of your test methods calls {@link #startService ServiceTestCase.startService()} 61 * or {@link #bindService ServiceTestCase.bindService()}, the test case calls 62 * {@link android.app.Service#onCreate() Service.onCreate()} and then calls either 63 * {@link android.app.Service#startService(Intent) Service.startService(Intent)} or 64 * {@link android.app.Service#bindService(Intent, ServiceConnection, int) 65 * Service.bindService(Intent, ServiceConnection, int)}, as appropriate. It also stores 66 * values needed to track and support the lifecycle. 67 * </li> 68 * <li> 69 * After each test method finishes, the test case calls the {@link #tearDown} method. This 70 * method stops and destroys the service with the appropriate calls, depending on how the 71 * service was started. If you override <code>tearDown()</code>, your must call the 72 * <code>super.tearDown()</code> as the last statement in your override. 73 * </li> 74 * </ul> 75 * 76 * <p> 77 * <strong>Dependency Injection.</strong> 78 * A service has two inherent dependencies, its {@link android.content.Context Context} and its 79 * associated {@link android.app.Application Application}. The ServiceTestCase framework 80 * allows you to inject modified, mock, or isolated replacements for these dependencies, and 81 * thus perform unit tests with controlled dependencies in an isolated environment. 82 * </p> 83 * <p> 84 * By default, the test case is injected with a full system context and a generic 85 * {@link android.test.mock.MockApplication MockApplication} object. You can inject 86 * alternatives to either of these by invoking 87 * {@link AndroidTestCase#setContext(Context) setContext()} or 88 * {@link #setApplication setApplication()}. You must do this <em>before</em> calling 89 * startService() or bindService(). The test framework provides a 90 * number of alternatives for Context, including 91 * {@link android.test.mock.MockContext MockContext}, 92 * {@link android.test.RenamingDelegatingContext RenamingDelegatingContext}, 93 * {@link android.content.ContextWrapper ContextWrapper}, and 94 * {@link android.test.IsolatedContext}. 95 * 96 * @deprecated Use 97 * <a href="{@docRoot}reference/android/support/test/rule/ServiceTestRule.html"> 98 * ServiceTestRule</a> instead. New tests should be written using the 99 * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. 100 */ 101 @Deprecated 102 public abstract class ServiceTestCase<T extends Service> extends AndroidTestCase { 103 104 Class<T> mServiceClass; 105 106 private Context mSystemContext; 107 private Application mApplication; 108 109 /** 110 * Constructor 111 * @param serviceClass The type of the service under test. 112 */ 113 public ServiceTestCase(Class<T> serviceClass) { 114 mServiceClass = serviceClass; 115 } 116 117 private T mService; 118 private boolean mServiceAttached = false; 119 private boolean mServiceCreated = false; 120 private boolean mServiceStarted = false; 121 private boolean mServiceBound = false; 122 private Intent mServiceIntent = null; 123 private int mServiceId; 124 125 /** 126 * @return An instance of the service under test. This instance is created automatically when 127 * a test calls {@link #startService} or {@link #bindService}. 128 */ 129 public T getService() { 130 return mService; 131 } 132 133 /** 134 * Gets the current system context and stores it. 135 * 136 * Extend this method to do your own test initialization. If you do so, you 137 * must call <code>super.setUp()</code> as the first statement in your override. The method is 138 * called before each test method is executed. 139 */ 140 @Override 141 protected void setUp() throws Exception { 142 super.setUp(); 143 144 // get the real context, before the individual tests have a chance to muck with it 145 mSystemContext = getContext(); 146 147 } 148 149 /** 150 * Creates the service under test and attaches all injected dependencies 151 * (Context, Application) to it. This is called automatically by {@link #startService} or 152 * by {@link #bindService}. 153 * If you need to call {@link AndroidTestCase#setContext(Context) setContext()} or 154 * {@link #setApplication setApplication()}, do so before calling this method. 155 */ 156 protected void setupService() { 157 mService = null; 158 try { 159 mService = mServiceClass.newInstance(); 160 } catch (Exception e) { 161 assertNotNull(mService); 162 } 163 if (getApplication() == null) { 164 setApplication(new MockApplication()); 165 } 166 mService.attach( 167 getContext(), 168 null, // ActivityThread not actually used in Service 169 mServiceClass.getName(), 170 null, // token not needed when not talking with the activity manager 171 getApplication(), 172 null // mocked services don't talk with the activity manager 173 ); 174 175 assertNotNull(mService); 176 177 mServiceId = new Random().nextInt(); 178 mServiceAttached = true; 179 } 180 181 /** 182 * Starts the service under test, in the same way as if it were started by 183 * {@link android.content.Context#startService(Intent) Context.startService(Intent)} with 184 * an {@link android.content.Intent} that identifies a service. 185 * If you use this method to start the service, it is automatically stopped by 186 * {@link #tearDown}. 187 * 188 * @param intent An Intent that identifies a service, of the same form as the Intent passed to 189 * {@link android.content.Context#startService(Intent) Context.startService(Intent)}. 190 */ 191 protected void startService(Intent intent) { 192 if (!mServiceAttached) { 193 setupService(); 194 } 195 assertNotNull(mService); 196 197 if (!mServiceCreated) { 198 mService.onCreate(); 199 mServiceCreated = true; 200 } 201 mService.onStartCommand(intent, 0, mServiceId); 202 203 mServiceStarted = true; 204 } 205 206 /** 207 * <p> 208 * Starts the service under test, in the same way as if it were started by 209 * {@link android.content.Context#bindService(Intent, ServiceConnection, int) 210 * Context.bindService(Intent, ServiceConnection, flags)} with an 211 * {@link android.content.Intent} that identifies a service. 212 * </p> 213 * <p> 214 * Notice that the parameters are different. You do not provide a 215 * {@link android.content.ServiceConnection} object or the flags parameter. Instead, 216 * you only provide the Intent. The method returns an object whose type is a 217 * subclass of {@link android.os.IBinder}, or null if the method fails. An IBinder 218 * object refers to a communication channel between the application and 219 * the service. The flag is assumed to be {@link android.content.Context#BIND_AUTO_CREATE}. 220 * </p> 221 * <p> 222 * See <a href="{@docRoot}guide/components/aidl.html">Designing a Remote Interface 223 * Using AIDL</a> for more information about the communication channel object returned 224 * by this method. 225 * </p> 226 * Note: To be able to use bindService in a test, the service must implement getService() 227 * method. An example of this is in the ApiDemos sample application, in the 228 * LocalService demo. 229 * 230 * @param intent An Intent object of the form expected by 231 * {@link android.content.Context#bindService}. 232 * 233 * @return An object whose type is a subclass of IBinder, for making further calls into 234 * the service. 235 */ 236 protected IBinder bindService(Intent intent) { 237 if (!mServiceAttached) { 238 setupService(); 239 } 240 assertNotNull(mService); 241 242 if (!mServiceCreated) { 243 mService.onCreate(); 244 mServiceCreated = true; 245 } 246 // no extras are expected by unbind 247 mServiceIntent = intent.cloneFilter(); 248 IBinder result = mService.onBind(intent); 249 250 mServiceBound = true; 251 return result; 252 } 253 254 /** 255 * Makes the necessary calls to stop (or unbind) the service under test, and 256 * calls onDestroy(). Ordinarily this is called automatically (by {@link #tearDown}, but 257 * you can call it directly from your test in order to check for proper shutdown behavior. 258 */ 259 protected void shutdownService() { 260 if (mServiceStarted) { 261 mService.stopSelf(); 262 mServiceStarted = false; 263 } else if (mServiceBound) { 264 mService.onUnbind(mServiceIntent); 265 mServiceBound = false; 266 } 267 if (mServiceCreated) { 268 mService.onDestroy(); 269 mServiceCreated = false; 270 } 271 } 272 273 /** 274 * <p> 275 * Shuts down the service under test. Ensures all resources are cleaned up and 276 * garbage collected before moving on to the next test. This method is called after each 277 * test method. 278 * </p> 279 * <p> 280 * Subclasses that override this method must call <code>super.tearDown()</code> as their 281 * last statement. 282 * </p> 283 * 284 * @throws Exception 285 */ 286 @Override 287 protected void tearDown() throws Exception { 288 shutdownService(); 289 mService = null; 290 291 // Scrub out members - protects against memory leaks in the case where someone 292 // creates a non-static inner class (thus referencing the test case) and gives it to 293 // someone else to hold onto 294 scrubClass(ServiceTestCase.class); 295 296 super.tearDown(); 297 } 298 299 /** 300 * Sets the application that is used during the test. If you do not call this method, 301 * a new {@link android.test.mock.MockApplication MockApplication} object is used. 302 * 303 * @param application The Application object that is used by the service under test. 304 * 305 * @see #getApplication() 306 */ 307 public void setApplication(Application application) { 308 mApplication = application; 309 } 310 311 /** 312 * Returns the Application object in use by the service under test. 313 * 314 * @return The application object. 315 * 316 * @see #setApplication 317 */ 318 public Application getApplication() { 319 return mApplication; 320 } 321 322 /** 323 * Returns the real system context that is saved by {@link #setUp()}. Use it to create 324 * mock or other types of context objects for the service under test. 325 * 326 * @return A normal system context. 327 */ 328 public Context getSystemContext() { 329 return mSystemContext; 330 } 331 332 /** 333 * Tests that {@link #setupService()} runs correctly and issues an 334 * {@link junit.framework.Assert#assertNotNull(String, Object)} if it does. 335 * You can override this test method if you wish. 336 * 337 * @throws Exception 338 */ 339 public void testServiceTestCaseSetUpProperly() throws Exception { 340 setupService(); 341 assertNotNull("service should be launched successfully", mService); 342 } 343 } 344