summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/test/InstrumentationTestCase.java26
-rw-r--r--core/java/android/test/RepetitiveTest.java40
-rw-r--r--test-runner/src/android/test/InstrumentationTestRunner.java26
3 files changed, 82 insertions, 10 deletions
diff --git a/core/java/android/test/InstrumentationTestCase.java b/core/java/android/test/InstrumentationTestCase.java
index cd33d8a..ca427ea 100644
--- a/core/java/android/test/InstrumentationTestCase.java
+++ b/core/java/android/test/InstrumentationTestCase.java
@@ -54,7 +54,7 @@ public class InstrumentationTestCase extends TestCase {
* @param instrumentation the instrumentation to use with this instance
*
* @deprecated Incorrect spelling,
- * use {@link #injectInstrumentation(android.app.Instrumentation) instead.
+ * use {@link #injectInstrumentation(android.app.Instrumentation)} instead.
*/
@Deprecated
public void injectInsrumentation(Instrumentation instrumentation) {
@@ -170,18 +170,23 @@ public class InstrumentationTestCase extends TestCase {
}
int runCount = 1;
+ boolean isRepetitive = false;
if (method.isAnnotationPresent(FlakyTest.class)) {
runCount = method.getAnnotation(FlakyTest.class).tolerance();
+ } else if (method.isAnnotationPresent(RepetitiveTest.class)) {
+ runCount = method.getAnnotation(RepetitiveTest.class).numIterations();
+ isRepetitive = true;
}
if (method.isAnnotationPresent(UiThreadTest.class)) {
final int tolerance = runCount;
+ final boolean repetitive = isRepetitive;
final Method testMethod = method;
final Throwable[] exceptions = new Throwable[1];
getInstrumentation().runOnMainSync(new Runnable() {
public void run() {
try {
- runMethod(testMethod, tolerance);
+ runMethod(testMethod, tolerance, repetitive);
} catch (Throwable throwable) {
exceptions[0] = throwable;
}
@@ -191,11 +196,16 @@ public class InstrumentationTestCase extends TestCase {
throw exceptions[0];
}
} else {
- runMethod(method, runCount);
+ runMethod(method, runCount, isRepetitive);
}
}
+ // For backwards-compatibility after adding isRepetitive
private void runMethod(Method runMethod, int tolerance) throws Throwable {
+ runMethod(runMethod, tolerance, false);
+ }
+
+ private void runMethod(Method runMethod, int tolerance, boolean isRepetitive) throws Throwable {
Throwable exception = null;
int runCount = 0;
@@ -211,8 +221,14 @@ public class InstrumentationTestCase extends TestCase {
exception = e;
} finally {
runCount++;
+ // Report current iteration number, if test is repetitive
+ if (isRepetitive) {
+ Bundle iterations = new Bundle();
+ iterations.putInt("currentiterations", runCount);
+ getInstrumentation().sendStatus(2, iterations);
+ }
}
- } while ((runCount < tolerance) && (exception != null));
+ } while ((runCount < tolerance) && (isRepetitive || exception != null));
if (exception != null) {
throw exception;
@@ -344,4 +360,4 @@ public class InstrumentationTestCase extends TestCase {
Runtime.getRuntime().gc();
super.tearDown();
}
-}
+} \ No newline at end of file
diff --git a/core/java/android/test/RepetitiveTest.java b/core/java/android/test/RepetitiveTest.java
new file mode 100644
index 0000000..6a7130e
--- /dev/null
+++ b/core/java/android/test/RepetitiveTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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 android.test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation can be used on an {@link android.test.InstrumentationTestCase}'s test methods.
+ * When the annotation is present, the test method is executed the number of times specified by
+ * numIterations and defaults to 1.
+ *
+ * {@hide} Not needed for public API.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RepetitiveTest {
+ /**
+ * Indicates the number of times a test case should be run.
+ *
+ * @return The total number of iterations, the default is 1.
+ */
+ int numIterations() default 1;
+} \ No newline at end of file
diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
index 70d1643..3ac74f7 100644
--- a/test-runner/src/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -240,6 +240,11 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
private static final String REPORT_KEY_RUN_TIME = "runtime";
/**
* If included in the status or final bundle sent to an IInstrumentationWatcher, this key
+ * reports the number of total iterations of the current test.
+ */
+ private static final String REPORT_KEY_NUM_ITERATIONS = "numiterations";
+ /**
+ * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
* reports the guessed suite assignment for the current test.
*/
private static final String REPORT_KEY_SUITE_ASSIGNMENT = "suiteassignment";
@@ -748,6 +753,20 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, "");
}
+ Method testMethod = null;
+ try {
+ testMethod = test.getClass().getMethod(testName);
+ // Report total number of iterations, if test is repetitive
+ if (testMethod.isAnnotationPresent(RepetitiveTest.class)) {
+ int numIterations = testMethod.getAnnotation(
+ RepetitiveTest.class).numIterations();
+ mTestResult.putInt(REPORT_KEY_NUM_ITERATIONS, numIterations);
+ }
+ } catch (NoSuchMethodException e) {
+ // ignore- the test with given name does not exist. Will be handled during test
+ // execution
+ }
+
// The delay_msec parameter is normally used to provide buffers of idle time
// for power measurement purposes. To make sure there is a delay before and after
// every test in a suite, we delay *after* every test (see endTest below) and also
@@ -766,9 +785,9 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
mIncludeDetailedStats = false;
try {
// Look for TimedTest annotation on both test class and test method
- if (test.getClass().getMethod(testName).isAnnotationPresent(TimedTest.class)) {
+ if (testMethod.isAnnotationPresent(TimedTest.class)) {
mIsTimedTest = true;
- mIncludeDetailedStats = test.getClass().getMethod(testName).getAnnotation(
+ mIncludeDetailedStats = testMethod.getAnnotation(
TimedTest.class).includeDetailedStats();
} else if (test.getClass().isAnnotationPresent(TimedTest.class)) {
mIsTimedTest = true;
@@ -778,9 +797,6 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
} catch (SecurityException e) {
// ignore - the test with given name cannot be accessed. Will be handled during
// test execution
- } catch (NoSuchMethodException e) {
- // ignore- the test with given name does not exist. Will be handled during test
- // execution
}
if (mIsTimedTest && mIncludeDetailedStats) {