/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.test; import android.app.Application; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import android.test.mock.MockApplication; import java.lang.reflect.Field; import java.util.Random; /** * This test case provides a framework in which you can test Service classes in * a controlled environment. It provides basic support for the lifecycle of a * Service, and hooks with which you can inject various dependencies and control * the environment in which your Service is tested. * *
Lifecycle Support.
* A Service is accessed with a specific sequence of
* calls, as described in the
* Services
* document. In order to support the lifecycle of a Service,
* ServiceTestCase
enforces this protocol:
*
*
setUp()
, you must call
* super.setUp()
as the first statement in your override.
* tearDown()
, your must call the
* super.tearDown()
as the last statement in your override.
* * Dependency Injection. * A service has two inherent dependencies, its {@link android.content.Context Context} and its * associated {@link android.app.Application Application}. The ServiceTestCase framework * allows you to inject modified, mock, or isolated replacements for these dependencies, and * thus perform unit tests with controlled dependencies in an isolated environment. *
*
* By default, the test case is injected with a full system context and a generic
* {@link android.test.mock.MockApplication MockApplication} object. You can inject
* alternatives to either of these by invoking
* {@link AndroidTestCase#setContext(Context) setContext()} or
* {@link #setApplication setApplication()}. You must do this before calling
* startService() or bindService(). The test framework provides a
* number of alternatives for Context, including
* {link android.test.mock.MockContext MockContext},
* {@link android.test.RenamingDelegatingContext RenamingDelegatingContext},
* {@link android.content.ContextWrapper ContextWrapper}, and
* {@link android.test.IsolatedContext}.
*/
public abstract class ServiceTestCase
* Starts the service under test, in the same way as if it were started by
* {@link android.content.Context#bindService(Intent, ServiceConnection, int)
* Context.bindService(Intent, ServiceConnection, flags)} with an
* {@link android.content.Intent} that identifies a service.
*
* Notice that the parameters are different. You do not provide a
* {@link android.content.ServiceConnection} object or the flags parameter. Instead,
* you only provide the Intent. The method returns an object whose type is a
* subclass of {@link android.os.IBinder}, or null if the method fails. An IBinder
* object refers to a communication channel between the application and
* the service. The flag is assumed to be {@link android.content.Context#BIND_AUTO_CREATE}.
*
* See Designing a Remote Interface
* Using AIDL for more information about the communication channel object returned
* by this method.
*
* Shuts down the service under test. Ensures all resources are cleaned up and
* garbage collected before moving on to the next test. This method is called after each
* test method.
*
* Subclasses that override this method must call super.setUp()
as the first statement in your override. The method is
* called before each test method is executed.
*/
@Override
protected void setUp() throws Exception {
super.setUp();
// get the real context, before the individual tests have a chance to muck with it
mSystemContext = getContext();
}
/**
* Creates the service under test and attaches all injected dependencies
* (Context, Application) to it. This is called automatically by {@link #startService} or
* by {@link #bindService}.
* If you need to call {@link AndroidTestCase#setContext(Context) setContext()} or
* {@link #setApplication setApplication()}, do so before calling this method.
*/
protected void setupService() {
mService = null;
try {
mService = mServiceClass.newInstance();
} catch (Exception e) {
assertNotNull(mService);
}
if (getApplication() == null) {
setApplication(new MockApplication());
}
mService.attach(
getContext(),
null, // ActivityThread not actually used in Service
mServiceClass.getName(),
null, // token not needed when not talking with the activity manager
getApplication(),
null // mocked services don't talk with the activity manager
);
assertNotNull(mService);
mServiceId = new Random().nextInt();
mServiceAttached = true;
}
/**
* Starts the service under test, in the same way as if it were started by
* {@link android.content.Context#startService(Intent) Context.startService(Intent)} with
* an {@link android.content.Intent} that identifies a service.
* If you use this method to start the service, it is automatically stopped by
* {@link #tearDown}.
*
* @param intent An Intent that identifies a service, of the same form as the Intent passed to
* {@link android.content.Context#startService(Intent) Context.startService(Intent)}.
*/
protected void startService(Intent intent) {
if (!mServiceAttached) {
setupService();
}
assertNotNull(mService);
if (!mServiceCreated) {
mService.onCreate();
mServiceCreated = true;
}
mService.onStartCommand(intent, 0, mServiceId);
mServiceStarted = true;
}
/**
* super.tearDown()
as their
* last statement.
*