InstrumentationTestRunnerpublic class InstrumentationTestRunner extends android.app.Instrumentation implements TestSuiteProviderAn {@link Instrumentation} that runs various types of {@link junit.framework.TestCase}s against
an Android package (application). Typical usage:
- Write {@link junit.framework.TestCase}s that perform unit, functional, or performance tests
against the classes in your package. Typically these are subclassed from:
- {@link android.test.ActivityInstrumentationTestCase}
- {@link android.test.ActivityUnitTestCase}
- {@link android.test.AndroidTestCase}
- {@link android.test.ApplicationTestCase}
- {@link android.test.InstrumentationTestCase}
- {@link android.test.ProviderTestCase}
- {@link android.test.ServiceTestCase}
- {@link android.test.SingleLaunchActivityTestCase}
- In an appropriate AndroidManifest.xml, define the this instrumentation with
the appropriate android:targetPackage set.
- Run the instrumentation using "adb shell am instrument -w",
with no optional arguments, to run all tests (except performance tests).
- Run the instrumentation using "adb shell am instrument -w",
with the argument '-e func true' to run all functional tests. These are tests that derive from
{@link android.test.InstrumentationTestCase}.
- Run the instrumentation using "adb shell am instrument -w",
with the argument '-e unit true' to run all unit tests. These are tests that do notderive
from {@link android.test.InstrumentationTestCase} (and are not performance tests).
- Run the instrumentation using "adb shell am instrument -w",
with the argument '-e class' set to run an individual {@link junit.framework.TestCase}.
Running all tests: adb shell am instrument -w
com.android.foo/android.test.InstrumentationTestRunner
Running all small tests: adb shell am instrument -w
-e size small
com.android.foo/android.test.InstrumentationTestRunner
Running all medium tests: adb shell am instrument -w
-e size medium
com.android.foo/android.test.InstrumentationTestRunner
Running all large tests: adb shell am instrument -w
-e size large
com.android.foo/android.test.InstrumentationTestRunner
Running a single testcase: adb shell am instrument -w
-e class com.android.foo.FooTest
com.android.foo/android.test.InstrumentationTestRunner
Running a single test: adb shell am instrument -w
-e class com.android.foo.FooTest#testFoo
com.android.foo/android.test.InstrumentationTestRunner
Running multiple tests: adb shell am instrument -w
-e class com.android.foo.FooTest,com.android.foo.TooTest
com.android.foo/android.test.InstrumentationTestRunner
Including performance tests: adb shell am instrument -w
-e perf true
com.android.foo/android.test.InstrumentationTestRunner
To debug your tests, set a break point in your code and pass:
-e debug true
To run in 'log only' mode
-e log true
This option will load and iterate through all test classes and methods, but will bypass actual
test execution. Useful for quickly obtaining info on the tests to be executed by an
instrumentation command.
To generate EMMA code coverage:
-e coverage true
Note: this requires an emma instrumented build. By default, the code coverage results file
will be saved as /sdcard/coverage.ec, unless overridden by coverageFile flag (see below)
To specify EMMA code coverage results file path:
-e coverageFile /sdcard/myFile.ec
in addition to the other arguments. |
Fields Summary |
---|
public static final String | ARGUMENT_TEST_CLASS | public static final String | ARGUMENT_TEST_PACKAGE | public static final String | ARGUMENT_TEST_SIZE_PREDICATE | public static final String | ARGUMENT_INCLUDE_PERF | public static final String | ARGUMENT_DELAY_MSEC | private static final String | SMALL_SUITE | private static final String | MEDIUM_SUITE | private static final String | LARGE_SUITE | private static final String | ARGUMENT_LOG_ONLY | private static final float | SMALL_SUITE_MAX_RUNTIMEThis constant defines the maximum allowed runtime (in ms) for a test included in the "small" suite.
It is used to make an educated guess at what suite an unlabeled test belongs. | private static final float | MEDIUM_SUITE_MAX_RUNTIMEThis constant defines the maximum allowed runtime (in ms) for a test included in the "medium" suite.
It is used to make an educated guess at what suite an unlabeled test belongs. | public static final String | REPORT_VALUE_IDThis value, if stored with key {@link android.app.Instrumentation#REPORT_KEY_IDENTIFIER},
identifies InstrumentationTestRunner as the source of the report. This is sent with all
status messages. | public static final String | REPORT_KEY_NUM_TOTALIf included in the status or final bundle sent to an IInstrumentationWatcher, this key
identifies the total number of tests that are being run. This is sent with all status
messages. | public static final String | REPORT_KEY_NUM_CURRENTIf included in the status or final bundle sent to an IInstrumentationWatcher, this key
identifies the sequence number of the current test. This is sent with any status message
describing a specific test being started or completed. | public static final String | REPORT_KEY_NAME_CLASSIf included in the status or final bundle sent to an IInstrumentationWatcher, this key
identifies the name of the current test class. This is sent with any status message
describing a specific test being started or completed. | public static final String | REPORT_KEY_NAME_TESTIf included in the status or final bundle sent to an IInstrumentationWatcher, this key
identifies the name of the current test. This is sent with any status message
describing a specific test being started or completed. | private static final String | REPORT_KEY_RUN_TIMEIf included in the status or final bundle sent to an IInstrumentationWatcher, this key
reports the run time in seconds of the current test. | private static final String | REPORT_KEY_SUITE_ASSIGNMENTIf included in the status or final bundle sent to an IInstrumentationWatcher, this key
reports the guessed suite assignment for the current test. | public static final int | REPORT_VALUE_RESULT_STARTThe test is starting. | public static final int | REPORT_VALUE_RESULT_OKThe test completed successfully. | public static final int | REPORT_VALUE_RESULT_ERRORThe test completed with an error. | public static final int | REPORT_VALUE_RESULT_FAILUREThe test completed with a failure. | public static final String | REPORT_KEY_STACKIf included in the status bundle sent to an IInstrumentationWatcher, this key
identifies a stack trace describing an error or failure. This is sent with any status
message describing a specific test being completed. | private static final String | DEFAULT_COVERAGE_FILE_PATH | private static final String | LOG_TAG | private final android.os.Bundle | mResults | private AndroidTestRunner | mTestRunner | private boolean | mDebug | private boolean | mJustCount | private boolean | mSuiteAssignmentMode | private int | mTestCount | private String | mPackageOfTests | private boolean | mCoverage | private String | mCoverageFilePath | private int | mDelayMsec |
Methods Summary |
---|
private void | generateCoverageReport()
// use reflection to call emma dump coverage method, to avoid
// always statically compiling against emma jar
java.io.File coverageFile = new java.io.File(getCoverageFilePath());
try {
Class emmaRTClass = Class.forName("com.vladium.emma.rt.RT");
Method dumpCoverageMethod = emmaRTClass.getMethod("dumpCoverageData",
coverageFile.getClass(), boolean.class, boolean.class);
dumpCoverageMethod.invoke(null, coverageFile, false, false);
} catch (ClassNotFoundException e) {
reportEmmaError("Is emma jar on classpath?", e);
} catch (SecurityException e) {
reportEmmaError(e);
} catch (NoSuchMethodException e) {
reportEmmaError(e);
} catch (IllegalArgumentException e) {
reportEmmaError(e);
} catch (IllegalAccessException e) {
reportEmmaError(e);
} catch (InvocationTargetException e) {
reportEmmaError(e);
}
| public junit.framework.TestSuite | getAllTests()Override this to define all of the tests to run in your package.
return null;
| protected AndroidTestRunner | getAndroidTestRunner()
return new AndroidTestRunner();
| private boolean | getBooleanArgument(android.os.Bundle arguments, java.lang.String tag)
String tagString = arguments.getString(tag);
return tagString != null && Boolean.parseBoolean(tagString);
| java.util.List | getBuilderRequirements()
return new ArrayList<Predicate<TestMethod>>();
| private java.lang.String | getCoverageFilePath()
if (mCoverageFilePath == null) {
return DEFAULT_COVERAGE_FILE_PATH;
}
else {
return mCoverageFilePath;
}
| public java.lang.ClassLoader | getLoader()Override this to provide access to the class loader of your package.
return null;
| private com.android.internal.util.Predicate | getSizePredicateFromArg(java.lang.String sizeArg)
if (SMALL_SUITE.equals(sizeArg)) {
return TestPredicates.SELECT_SMALL;
} else if (MEDIUM_SUITE.equals(sizeArg)) {
return TestPredicates.SELECT_MEDIUM;
} else if (LARGE_SUITE.equals(sizeArg)) {
return TestPredicates.SELECT_LARGE;
} else {
return null;
}
| public junit.framework.TestSuite | getTestSuite()
return getAllTests();
| public void | onCreate(android.os.Bundle arguments)
super.onCreate(arguments);
// Apk paths used to search for test classes when using TestSuiteBuilders.
String[] apkPaths =
{getTargetContext().getPackageCodePath(), getContext().getPackageCodePath()};
ClassPathPackageInfoSource.setApkPaths(apkPaths);
Predicate<TestMethod> testSizePredicate = null;
boolean includePerformance = false;
String testClassesArg = null;
boolean logOnly = false;
if (arguments != null) {
// Test class name passed as an argument should override any meta-data declaration.
testClassesArg = arguments.getString(ARGUMENT_TEST_CLASS);
mDebug = getBooleanArgument(arguments, "debug");
mJustCount = getBooleanArgument(arguments, "count");
mSuiteAssignmentMode = getBooleanArgument(arguments, "suiteAssignment");
mPackageOfTests = arguments.getString(ARGUMENT_TEST_PACKAGE);
testSizePredicate = getSizePredicateFromArg(
arguments.getString(ARGUMENT_TEST_SIZE_PREDICATE));
includePerformance = getBooleanArgument(arguments, ARGUMENT_INCLUDE_PERF);
logOnly = getBooleanArgument(arguments, ARGUMENT_LOG_ONLY);
mCoverage = getBooleanArgument(arguments, "coverage");
mCoverageFilePath = arguments.getString("coverageFile");
try {
Object delay = arguments.get(ARGUMENT_DELAY_MSEC); // Accept either string or int
if (delay != null) mDelayMsec = Integer.parseInt(delay.toString());
} catch (NumberFormatException e) {
Log.e(LOG_TAG, "Invalid delay_msec parameter", e);
}
}
TestSuiteBuilder testSuiteBuilder = new TestSuiteBuilder(getClass().getName(),
getTargetContext().getClassLoader());
if (testSizePredicate != null) {
testSuiteBuilder.addRequirements(testSizePredicate);
}
if (!includePerformance) {
testSuiteBuilder.addRequirements(REJECT_PERFORMANCE);
}
if (testClassesArg == null) {
if (mPackageOfTests != null) {
testSuiteBuilder.includePackages(mPackageOfTests);
} else {
TestSuite testSuite = getTestSuite();
if (testSuite != null) {
testSuiteBuilder.addTestSuite(testSuite);
} else {
// no package or class bundle arguments were supplied, and no test suite
// provided so add all tests in application
testSuiteBuilder.includePackages("");
}
}
} else {
parseTestClasses(testClassesArg, testSuiteBuilder);
}
testSuiteBuilder.addRequirements(getBuilderRequirements());
mTestRunner = getAndroidTestRunner();
mTestRunner.setContext(getTargetContext());
mTestRunner.setInstrumentaiton(this);
mTestRunner.setSkipExecution(logOnly);
mTestRunner.setTest(testSuiteBuilder.build());
mTestCount = mTestRunner.getTestCases().size();
if (mSuiteAssignmentMode) {
mTestRunner.addTestListener(new SuiteAssignmentPrinter());
} else {
mTestRunner.addTestListener(new TestPrinter("TestRunner", false));
mTestRunner.addTestListener(new WatcherResultPrinter(mTestCount));
}
start();
| public void | onStart()
Looper.prepare();
if (mJustCount) {
mResults.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
mResults.putInt(REPORT_KEY_NUM_TOTAL, mTestCount);
finish(Activity.RESULT_OK, mResults);
} else {
if (mDebug) {
Debug.waitForDebugger();
}
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PrintStream writer = new PrintStream(byteArrayOutputStream);
try {
StringResultPrinter resultPrinter = new StringResultPrinter(writer);
mTestRunner.addTestListener(resultPrinter);
long startTime = System.currentTimeMillis();
mTestRunner.runTest();
long runTime = System.currentTimeMillis() - startTime;
resultPrinter.print(mTestRunner.getTestResult(), runTime);
} finally {
mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
String.format("\nTest results for %s=%s",
mTestRunner.getTestClassName(),
byteArrayOutputStream.toString()));
if (mCoverage) {
generateCoverageReport();
}
writer.close();
finish(Activity.RESULT_OK, mResults);
}
}
| private void | parseTestClass(java.lang.String testClassName, android.test.suitebuilder.TestSuiteBuilder testSuiteBuilder)Parse and load the given test class and, optionally, method
int methodSeparatorIndex = testClassName.indexOf('#");
String testMethodName = null;
if (methodSeparatorIndex > 0) {
testMethodName = testClassName.substring(methodSeparatorIndex + 1);
testClassName = testClassName.substring(0, methodSeparatorIndex);
}
testSuiteBuilder.addTestClassByName(testClassName, testMethodName,
getTargetContext());
| private void | parseTestClasses(java.lang.String testClassArg, android.test.suitebuilder.TestSuiteBuilder testSuiteBuilder)Parses and loads the specified set of test classes
String[] testClasses = testClassArg.split(",");
for (String testClass : testClasses) {
parseTestClass(testClass, testSuiteBuilder);
}
| private void | reportEmmaError(java.lang.Exception e)
reportEmmaError("", e);
| private void | reportEmmaError(java.lang.String hint, java.lang.Exception e)
String msg = "Failed to generate emma coverage. " + hint;
Log.e(LOG_TAG, msg, e);
mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT, "\nError: " + msg);
|
|