blob: 8fad5d670dcd3c30399bc9d65ff5d1314c2f0a9f [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.test;
18
19import android.app.Application;
20import android.app.Service;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.os.IBinder;
25import android.os.RemoteException;
26import android.test.mock.MockApplication;
27
28import java.lang.reflect.Field;
29import java.util.Random;
30
31/**
32 * This test case provides a framework in which you can test Service classes in
33 * a controlled environment. It provides basic support for the lifecycle of a
Joe Malin7d433aa2010-05-31 14:37:28 -070034 * Service, and hooks with which you can inject various dependencies and control
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035 * the environment in which your Service is tested.
36 *
37 * <p><b>Lifecycle Support.</b>
Joe Malin7d433aa2010-05-31 14:37:28 -070038 * A Service is accessed with a specific sequence of
Scott Main7aee61f2011-02-08 11:25:01 -080039 * calls, as described in the
40 * <a href="http://developer.android.com/guide/topics/fundamentals/services.html">Services</a>
41 * document. In order to support the lifecycle of a Service,
Joe Malin7d433aa2010-05-31 14:37:28 -070042 * <code>ServiceTestCase</code> enforces this protocol:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043 *
Joe Malin7d433aa2010-05-31 14:37:28 -070044 * <ul>
45 * <li>
46 * The {@link #setUp()} method is called before each test method. The base implementation
47 * gets the system context. If you override <code>setUp()</code>, you must call
48 * <code>super.setUp()</code> as the first statement in your override.
49 * </li>
50 * <li>
51 * The test case waits to call {@link android.app.Service#onCreate()} until one of your
52 * test methods calls {@link #startService} or {@link #bindService}. This gives you an
53 * opportunity to set up or adjust any additional framework or test logic before you test
54 * the running service.
55 * </li>
56 * <li>
57 * When one of your test methods calls {@link #startService ServiceTestCase.startService()}
58 * or {@link #bindService ServiceTestCase.bindService()}, the test case calls
59 * {@link android.app.Service#onCreate() Service.onCreate()} and then calls either
60 * {@link android.app.Service#startService(Intent) Service.startService(Intent)} or
61 * {@link android.app.Service#bindService(Intent, ServiceConnection, int)
62 * Service.bindService(Intent, ServiceConnection, int)}, as appropriate. It also stores
63 * values needed to track and support the lifecycle.
64 * </li>
65 * <li>
66 * After each test method finishes, the test case calls the {@link #tearDown} method. This
67 * method stops and destroys the service with the appropriate calls, depending on how the
68 * service was started. If you override <code>tearDown()</code>, your must call the
69 * <code>super.tearDown()</code> as the last statement in your override.
70 * </li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 * </ul>
Joe Malin7d433aa2010-05-31 14:37:28 -070072 *
73 * <p>
74 * <strong>Dependency Injection.</strong>
75 * A service has two inherent dependencies, its {@link android.content.Context Context} and its
76 * associated {@link android.app.Application Application}. The ServiceTestCase framework
77 * allows you to inject modified, mock, or isolated replacements for these dependencies, and
78 * thus perform unit tests with controlled dependencies in an isolated environment.
79 * </p>
80 * <p>
81 * By default, the test case is injected with a full system context and a generic
82 * {@link android.test.mock.MockApplication MockApplication} object. You can inject
83 * alternatives to either of these by invoking
84 * {@link AndroidTestCase#setContext(Context) setContext()} or
85 * {@link #setApplication setApplication()}. You must do this <em>before</em> calling
86 * startService() or bindService(). The test framework provides a
87 * number of alternatives for Context, including
88 * {link android.test.mock.MockContext MockContext},
89 * {@link android.test.RenamingDelegatingContext RenamingDelegatingContext},
90 * {@link android.content.ContextWrapper ContextWrapper}, and
91 * {@link android.test.IsolatedContext}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 */
93public abstract class ServiceTestCase<T extends Service> extends AndroidTestCase {
94
95 Class<T> mServiceClass;
96
97 private Context mSystemContext;
98 private Application mApplication;
99
Joe Malin7d433aa2010-05-31 14:37:28 -0700100 /**
101 * Constructor
102 * @param serviceClass The type of the service under test.
103 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 public ServiceTestCase(Class<T> serviceClass) {
105 mServiceClass = serviceClass;
106 }
107
108 private T mService;
109 private boolean mServiceAttached = false;
110 private boolean mServiceCreated = false;
111 private boolean mServiceStarted = false;
112 private boolean mServiceBound = false;
113 private Intent mServiceIntent = null;
114 private int mServiceId;
115
116 /**
Joe Malin7d433aa2010-05-31 14:37:28 -0700117 * @return An instance of the service under test. This instance is created automatically when
118 * a test calls {@link #startService} or {@link #bindService}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 */
120 public T getService() {
121 return mService;
122 }
123
124 /**
Joe Malin7d433aa2010-05-31 14:37:28 -0700125 * Gets the current system context and stores it.
126 *
127 * Extend this method to do your own test initialization. If you do so, you
128 * must call <code>super.setUp()</code> as the first statement in your override. The method is
129 * called before each test method is executed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 */
131 @Override
132 protected void setUp() throws Exception {
133 super.setUp();
Joe Malin7d433aa2010-05-31 14:37:28 -0700134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 // get the real context, before the individual tests have a chance to muck with it
136 mSystemContext = getContext();
137
138 }
Joe Malin7d433aa2010-05-31 14:37:28 -0700139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 /**
Joe Malin7d433aa2010-05-31 14:37:28 -0700141 * Creates the service under test and attaches all injected dependencies
142 * (Context, Application) to it. This is called automatically by {@link #startService} or
143 * by {@link #bindService}.
144 * If you need to call {@link AndroidTestCase#setContext(Context) setContext()} or
145 * {@link #setApplication setApplication()}, do so before calling this method.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 */
147 protected void setupService() {
148 mService = null;
149 try {
150 mService = mServiceClass.newInstance();
151 } catch (Exception e) {
152 assertNotNull(mService);
153 }
154 if (getApplication() == null) {
155 setApplication(new MockApplication());
156 }
157 mService.attach(
158 getContext(),
159 null, // ActivityThread not actually used in Service
160 mServiceClass.getName(),
161 null, // token not needed when not talking with the activity manager
162 getApplication(),
163 null // mocked services don't talk with the activity manager
164 );
Joe Malin7d433aa2010-05-31 14:37:28 -0700165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 assertNotNull(mService);
Joe Malin7d433aa2010-05-31 14:37:28 -0700167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 mServiceId = new Random().nextInt();
169 mServiceAttached = true;
170 }
Joe Malin7d433aa2010-05-31 14:37:28 -0700171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 /**
Joe Malin7d433aa2010-05-31 14:37:28 -0700173 * Starts the service under test, in the same way as if it were started by
174 * {@link android.content.Context#startService(Intent) Context.startService(Intent)} with
175 * an {@link android.content.Intent} that identifies a service.
176 * If you use this method to start the service, it is automatically stopped by
177 * {@link #tearDown}.
178 *
179 * @param intent An Intent that identifies a service, of the same form as the Intent passed to
180 * {@link android.content.Context#startService(Intent) Context.startService(Intent)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 */
182 protected void startService(Intent intent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 if (!mServiceAttached) {
184 setupService();
185 }
186 assertNotNull(mService);
Joe Malin7d433aa2010-05-31 14:37:28 -0700187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 if (!mServiceCreated) {
189 mService.onCreate();
190 mServiceCreated = true;
191 }
Evan Millar71be4b52010-06-01 13:55:50 -0700192 mService.onStartCommand(intent, 0, mServiceId);
Joe Malin7d433aa2010-05-31 14:37:28 -0700193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 mServiceStarted = true;
195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196
Joe Malin7d433aa2010-05-31 14:37:28 -0700197 /**
198 * <p>
199 * Starts the service under test, in the same way as if it were started by
200 * {@link android.content.Context#bindService(Intent, ServiceConnection, int)
201 * Context.bindService(Intent, ServiceConnection, flags)} with an
202 * {@link android.content.Intent} that identifies a service.
203 * </p>
204 * <p>
205 * Notice that the parameters are different. You do not provide a
206 * {@link android.content.ServiceConnection} object or the flags parameter. Instead,
207 * you only provide the Intent. The method returns an object whose type is a
208 * subclass of {@link android.os.IBinder}, or null if the method fails. An IBinder
209 * object refers to a communication channel between the application and
210 * the service. The flag is assumed to be {@link android.content.Context#BIND_AUTO_CREATE}.
211 * </p>
212 * <p>
213 * See <a href="{@docRoot}guide/developing/tools/aidl.html">Designing a Remote Interface
214 * Using AIDL</a> for more information about the communication channel object returned
215 * by this method.
216 * </p>
217 * Note: To be able to use bindService in a test, the service must implement getService()
218 * method. An example of this is in the ApiDemos sample application, in the
219 * LocalService demo.
220 *
221 * @param intent An Intent object of the form expected by
222 * {@link android.content.Context#bindService}.
223 *
224 * @return An object whose type is a subclass of IBinder, for making further calls into
225 * the service.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 */
227 protected IBinder bindService(Intent intent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 if (!mServiceAttached) {
229 setupService();
230 }
231 assertNotNull(mService);
Joe Malin7d433aa2010-05-31 14:37:28 -0700232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 if (!mServiceCreated) {
234 mService.onCreate();
235 mServiceCreated = true;
236 }
237 // no extras are expected by unbind
238 mServiceIntent = intent.cloneFilter();
239 IBinder result = mService.onBind(intent);
Joe Malin7d433aa2010-05-31 14:37:28 -0700240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 mServiceBound = true;
242 return result;
243 }
Joe Malin7d433aa2010-05-31 14:37:28 -0700244
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 /**
Joe Malin7d433aa2010-05-31 14:37:28 -0700246 * Makes the necessary calls to stop (or unbind) the service under test, and
247 * calls onDestroy(). Ordinarily this is called automatically (by {@link #tearDown}, but
248 * you can call it directly from your test in order to check for proper shutdown behavior.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 */
250 protected void shutdownService() {
251 if (mServiceStarted) {
252 mService.stopSelf();
253 mServiceStarted = false;
254 } else if (mServiceBound) {
255 mService.onUnbind(mServiceIntent);
256 mServiceBound = false;
257 }
258 if (mServiceCreated) {
259 mService.onDestroy();
260 }
261 }
Joe Malin7d433aa2010-05-31 14:37:28 -0700262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 /**
Joe Malin7d433aa2010-05-31 14:37:28 -0700264 * <p>
265 * Shuts down the service under test. Ensures all resources are cleaned up and
266 * garbage collected before moving on to the next test. This method is called after each
267 * test method.
268 * </p>
269 * <p>
270 * Subclasses that override this method must call <code>super.tearDown()</code> as their
271 * last statement.
272 * </p>
273 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 * @throws Exception
275 */
276 @Override
277 protected void tearDown() throws Exception {
278 shutdownService();
279 mService = null;
280
Joe Malin7d433aa2010-05-31 14:37:28 -0700281 // Scrub out members - protects against memory leaks in the case where someone
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 // creates a non-static inner class (thus referencing the test case) and gives it to
283 // someone else to hold onto
284 scrubClass(ServiceTestCase.class);
285
286 super.tearDown();
287 }
Joe Malin7d433aa2010-05-31 14:37:28 -0700288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 /**
Joe Malin7d433aa2010-05-31 14:37:28 -0700290 * Sets the application that is used during the test. If you do not call this method,
291 * a new {@link android.test.mock.MockApplication MockApplication} object is used.
292 *
293 * @param application The Application object that is used by the service under test.
294 *
295 * @see #getApplication()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 */
297 public void setApplication(Application application) {
298 mApplication = application;
299 }
300
301 /**
Joe Malin7d433aa2010-05-31 14:37:28 -0700302 * Returns the Application object in use by the service under test.
303 *
304 * @return The application object.
305 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 * @see #setApplication
307 */
308 public Application getApplication() {
309 return mApplication;
310 }
Joe Malin7d433aa2010-05-31 14:37:28 -0700311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 /**
Joe Malin7d433aa2010-05-31 14:37:28 -0700313 * Returns the real system context that is saved by {@link #setUp()}. Use it to create
314 * mock or other types of context objects for the service under test.
315 *
316 * @return A normal system context.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 */
318 public Context getSystemContext() {
319 return mSystemContext;
320 }
321
Joe Malin7d433aa2010-05-31 14:37:28 -0700322 /**
323 * Tests that {@link #setupService()} runs correctly and issues an
324 * {@link junit.framework.Assert#assertNotNull(String, Object)} if it does.
325 * You can override this test method if you wish.
326 *
327 * @throws Exception
328 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 public void testServiceTestCaseSetUpProperly() throws Exception {
330 setupService();
331 assertNotNull("service should be launched successfully", mService);
332 }
333}