blob: fb3b68e51e6fae685e7bf77dc330f0b879693b92 [file] [log] [blame]
/*
* Copyright (C) 2010 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 com.android.tradefed.testtype;
import com.android.ddmlib.Log;
import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.ITestInvocationListener;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestResult;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Vector;
/**
* Helper JUnit test case that provides the {@link IRemoteTest} and {@link IDeviceTest} services.
* <p/>
* This is useful if you want to implement tests that follow the JUnit pattern of defining tests,
* and still have full support for other tradefed features such as {@link Option}s
*/
public class DeviceTestCase extends TestCase implements IDeviceTest, IRemoteTest {
private static final String LOG_TAG = "DeviceTestCase";
private ITestDevice mDevice;
@Option(name = "method", description = "run a specific test method.")
private String mMethodName = null;
private Vector<String> mMethodNames = null;
public DeviceTestCase() {
super();
}
public DeviceTestCase(String name) {
super(name);
}
/**
* {@inheritDoc}
*/
@Override
public ITestDevice getDevice() {
return mDevice;
}
/**
* {@inheritDoc}
*/
@Override
public void setDevice(ITestDevice device) {
mDevice = device;
}
/**
* {@inheritDoc}
* @throws DeviceNotAvailableException
*/
@Override
public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
if (getName() == null && mMethodName != null) {
setName(mMethodName);
}
JUnitRunUtil.runTest(listener, this);
}
@Override
public int countTestCases() {
// the superclass implementation always returns 1 - add logic to handle case where all tests
// should be run
if (getName() != null || mMethodName != null) {
return 1;
} else {
return getTestMethodNames().size();
}
}
/**
* Override parent method to run all test methods if test method to run is null.
* <p/>
* The JUnit framework only supports running all the tests in a TestCase by wrapping it in a
* TestSuite. Unfortunately with this mechanism callers can't control the lifecycle of their
* own test cases, which makes it impossible to do things like have the tradefed configuration
* framework inject options into a Test Case.
*/
@Override
public void run(TestResult result) {
// check if test method to run aka name is null
if (getName() == null) {
Collection<String> testMethodNames = getTestMethodNames();
for (String methodName : testMethodNames) {
setName(methodName);
CLog.d("Running %s#%s()", this.getClass().getName(), methodName);
super.run(result);
}
} else {
CLog.d("Running %s#%s()", this.getClass().getName(), getName());
super.run(result);
}
}
/**
* Get list of test methods to run
* @param class1
* @return
*/
private Collection<String> getTestMethodNames() {
if (mMethodNames == null) {
mMethodNames = new Vector<String>();
// Unfortunately {@link TestSuite} doesn't expose the functionality to find all test*
// methods,
// so needed to copy and paste code from TestSuite
Class<?> theClass = this.getClass();
Class<?> superClass = theClass;
while (Test.class.isAssignableFrom(superClass)) {
Method[] methods = superClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
addTestMethod(methods[i], mMethodNames, theClass);
}
superClass = superClass.getSuperclass();
}
if (mMethodNames.size() == 0) {
Log.w(LOG_TAG, String.format("No tests found in %s", theClass.getName()));
}
}
return mMethodNames;
}
private void addTestMethod(Method m, Vector<String> names, Class<?> theClass) {
String name = m.getName();
if (names.contains(name)) {
return;
}
if (!isPublicTestMethod(m)) {
if (isTestMethod(m)) {
Log.w(LOG_TAG, String.format("Test method isn't public: %s", m.getName()));
}
return;
}
names.addElement(name);
}
private boolean isPublicTestMethod(Method m) {
return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
}
private boolean isTestMethod(Method m) {
String name = m.getName();
Class<?>[] parameters = m.getParameterTypes();
Class<?> returnType = m.getReturnType();
return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE);
}
}