| /* | |
| * 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.Instrumentation; | |
| import android.content.Context; | |
| import android.os.Bundle; | |
| import android.test.mock.MockContext; | |
| import android.test.suitebuilder.ListTestCaseNames; | |
| import android.test.suitebuilder.ListTestCaseNames.TestDescriptor; | |
| import android.test.suitebuilder.annotation.SmallTest; | |
| import junit.framework.Test; | |
| import junit.framework.TestCase; | |
| import junit.framework.TestSuite; | |
| import java.util.List; | |
| /** | |
| * Tests for {@link InstrumentationTestRunner} | |
| */ | |
| @SmallTest | |
| public class InstrumentationTestRunnerTest extends TestCase { | |
| private StubInstrumentationTestRunner mInstrumentationTestRunner; | |
| private StubAndroidTestRunner mStubAndroidTestRunner; | |
| private String mTargetContextPackageName; | |
| protected void setUp() throws Exception { | |
| super.setUp(); | |
| mStubAndroidTestRunner = new StubAndroidTestRunner(); | |
| mTargetContextPackageName = "android.test.suitebuilder.examples"; | |
| mInstrumentationTestRunner = new StubInstrumentationTestRunner( | |
| new StubContext("com.google.foo.tests"), | |
| new StubContext(mTargetContextPackageName), mStubAndroidTestRunner); | |
| } | |
| public void testOverrideTestToRunWithClassArgument() throws Exception { | |
| String expectedTestClassName = PlaceHolderTest.class.getName(); | |
| mInstrumentationTestRunner.onCreate(createBundle( | |
| InstrumentationTestRunner.ARGUMENT_TEST_CLASS, expectedTestClassName)); | |
| assertTestRunnerCalledWithExpectedParameters(expectedTestClassName, "testPlaceHolder"); | |
| } | |
| public void testOverrideTestToRunWithClassAndMethodArgument() throws Exception { | |
| String expectedTestClassName = PlaceHolderTest.class.getName(); | |
| String expectedTestMethodName = "testPlaceHolder"; | |
| String classAndMethod = expectedTestClassName + "#" + expectedTestMethodName; | |
| mInstrumentationTestRunner.onCreate(createBundle( | |
| InstrumentationTestRunner.ARGUMENT_TEST_CLASS, classAndMethod)); | |
| assertTestRunnerCalledWithExpectedParameters(expectedTestClassName, | |
| expectedTestMethodName); | |
| } | |
| public void testUseSelfAsTestSuiteProviderWhenNoMetaDataOrClassArgument() throws Exception { | |
| TestSuite testSuite = new TestSuite(); | |
| testSuite.addTestSuite(PlaceHolderTest.class); | |
| mInstrumentationTestRunner.setAllTestsSuite(testSuite); | |
| mInstrumentationTestRunner.onCreate(null); | |
| assertTestRunnerCalledWithExpectedParameters( | |
| PlaceHolderTest.class.getName(), "testPlaceHolder"); | |
| } | |
| public void testMultipleTestClass() throws Exception { | |
| String classArg = PlaceHolderTest.class.getName() + "," + | |
| PlaceHolderTest2.class.getName(); | |
| mInstrumentationTestRunner.onCreate(createBundle( | |
| InstrumentationTestRunner.ARGUMENT_TEST_CLASS, classArg)); | |
| Test test = mStubAndroidTestRunner.getTest(); | |
| assertContentsInOrder(ListTestCaseNames.getTestNames((TestSuite) test), | |
| new TestDescriptor(PlaceHolderTest.class.getName(), "testPlaceHolder"), | |
| new TestDescriptor(PlaceHolderTest2.class.getName(), "testPlaceHolder2")); | |
| } | |
| /** | |
| * Test that runtime exceptions during runTest are handled gracefully | |
| */ | |
| public void testUnhandledException() throws Exception { | |
| StubAndroidTestRunner stubAndroidTestRunner = new StubAndroidTestRunner() { | |
| @Override | |
| public void runTest() { | |
| throw new RuntimeException(); | |
| } | |
| }; | |
| StubInstrumentationTestRunner instrumentationTestRunner = new StubInstrumentationTestRunner( | |
| new StubContext("com.google.foo.tests"), | |
| new StubContext(mTargetContextPackageName), stubAndroidTestRunner); | |
| instrumentationTestRunner.onCreate(new Bundle()); | |
| instrumentationTestRunner.onStart(); | |
| assertTrue("Instrumentation did not finish", instrumentationTestRunner.isFinished()); | |
| // ensure a meaningful error message placed in results | |
| String resultsData = instrumentationTestRunner.mResults.getString( | |
| Instrumentation.REPORT_KEY_STREAMRESULT); | |
| assertTrue("Instrumentation results is missing RuntimeException", | |
| resultsData.contains("RuntimeException")); | |
| } | |
| /** | |
| * Test that specifying a method which does not exist is handled gracefully | |
| */ | |
| public void testBadMethodArgument() throws Exception { | |
| String testClassName = PlaceHolderTest.class.getName(); | |
| String invalidMethodName = "testNoExist"; | |
| String classAndMethod = testClassName + "#" + invalidMethodName; | |
| mInstrumentationTestRunner.onCreate(createBundle( | |
| InstrumentationTestRunner.ARGUMENT_TEST_CLASS, classAndMethod)); | |
| assertTestRunnerCalledWithExpectedParameters(testClassName, | |
| invalidMethodName); | |
| } | |
| public void testDelayParameter() throws Exception { | |
| int delayMsec = 1000; | |
| Bundle args = new Bundle(); | |
| args.putInt(InstrumentationTestRunner.ARGUMENT_DELAY_MSEC, delayMsec); | |
| args.putString(InstrumentationTestRunner.ARGUMENT_TEST_CLASS, | |
| PlaceHolderTest.class.getName() + "," + | |
| PlaceHolderTest2.class.getName()); | |
| mInstrumentationTestRunner.onCreate(args); | |
| Thread t = new Thread() { public void run() { mInstrumentationTestRunner.onStart(); } }; | |
| // Should delay three times: before, between, and after the two tests. | |
| long beforeTest = System.currentTimeMillis(); | |
| t.start(); | |
| t.join(); | |
| assertTrue(System.currentTimeMillis() > beforeTest + delayMsec * 3); | |
| assertTrue(mInstrumentationTestRunner.isStarted()); | |
| assertTrue(mInstrumentationTestRunner.isFinished()); | |
| assertTrue(mStubAndroidTestRunner.isRun()); | |
| } | |
| /** | |
| * Test that the -e {@link InstrumentationTestRunner.ARGUMENT_ANNOTATION} parameter properly | |
| * selects tests. | |
| */ | |
| public void testAnnotationParameter() throws Exception { | |
| String expectedTestClassName = AnnotationTest.class.getName(); | |
| Bundle args = new Bundle(); | |
| args.putString(InstrumentationTestRunner.ARGUMENT_TEST_CLASS, expectedTestClassName); | |
| args.putString(InstrumentationTestRunner.ARGUMENT_ANNOTATION, FlakyTest.class.getName()); | |
| mInstrumentationTestRunner.onCreate(args); | |
| assertTestRunnerCalledWithExpectedParameters(expectedTestClassName, "testAnnotated"); | |
| } | |
| /** | |
| * Test that the -e {@link InstrumentationTestRunner.ARGUMENT_NOT_ANNOTATION} parameter | |
| * properly excludes tests. | |
| */ | |
| public void testNotAnnotationParameter() throws Exception { | |
| String expectedTestClassName = AnnotationTest.class.getName(); | |
| Bundle args = new Bundle(); | |
| args.putString(InstrumentationTestRunner.ARGUMENT_TEST_CLASS, expectedTestClassName); | |
| args.putString(InstrumentationTestRunner.ARGUMENT_NOT_ANNOTATION, | |
| FlakyTest.class.getName()); | |
| mInstrumentationTestRunner.onCreate(args); | |
| assertTestRunnerCalledWithExpectedParameters(expectedTestClassName, "testNotAnnotated"); | |
| } | |
| private void assertContentsInOrder(List<TestDescriptor> actual, TestDescriptor... source) { | |
| TestDescriptor[] clonedSource = source.clone(); | |
| assertEquals("Unexpected number of items.", clonedSource.length, actual.size()); | |
| for (int i = 0; i < actual.size(); i++) { | |
| TestDescriptor actualItem = actual.get(i); | |
| TestDescriptor sourceItem = clonedSource[i]; | |
| assertEquals("Unexpected item. Index: " + i, sourceItem, actualItem); | |
| } | |
| } | |
| private void assertTestRunnerCalledWithExpectedParameters( | |
| String expectedTestClassName, String expectedTestMethodName) { | |
| Test test = mStubAndroidTestRunner.getTest(); | |
| assertContentsInOrder(ListTestCaseNames.getTestNames((TestSuite) test), | |
| new TestDescriptor(expectedTestClassName, expectedTestMethodName)); | |
| assertTrue(mInstrumentationTestRunner.isStarted()); | |
| assertFalse(mInstrumentationTestRunner.isFinished()); | |
| } | |
| private Bundle createBundle(String key, String value) { | |
| Bundle bundle = new Bundle(); | |
| bundle.putString(key, value); | |
| return bundle; | |
| } | |
| private static class StubInstrumentationTestRunner extends InstrumentationTestRunner { | |
| private Context mContext; | |
| private Context mTargetContext; | |
| private boolean mStarted; | |
| private boolean mFinished; | |
| private AndroidTestRunner mAndroidTestRunner; | |
| private TestSuite mTestSuite; | |
| private TestSuite mDefaultTestSuite; | |
| private String mPackageNameForDefaultTests; | |
| private Bundle mResults; | |
| public StubInstrumentationTestRunner(Context context, Context targetContext, | |
| AndroidTestRunner androidTestRunner) { | |
| this.mContext = context; | |
| this.mTargetContext = targetContext; | |
| this.mAndroidTestRunner = androidTestRunner; | |
| } | |
| public Context getContext() { | |
| return mContext; | |
| } | |
| public TestSuite getAllTests() { | |
| return mTestSuite; | |
| } | |
| public Context getTargetContext() { | |
| return mTargetContext; | |
| } | |
| protected AndroidTestRunner getAndroidTestRunner() { | |
| return mAndroidTestRunner; | |
| } | |
| public void start() { | |
| mStarted = true; | |
| } | |
| public void finish(int resultCode, Bundle results) { | |
| mFinished = true; | |
| mResults = results; | |
| } | |
| public boolean isStarted() { | |
| return mStarted; | |
| } | |
| public boolean isFinished() { | |
| return mFinished; | |
| } | |
| public void setAllTestsSuite(TestSuite testSuite) { | |
| mTestSuite = testSuite; | |
| } | |
| public void setDefaultTestsSuite(TestSuite testSuite) { | |
| mDefaultTestSuite = testSuite; | |
| } | |
| public String getPackageNameForDefaultTests() { | |
| return mPackageNameForDefaultTests; | |
| } | |
| @Override | |
| void prepareLooper() { | |
| // ignore | |
| } | |
| } | |
| private static class StubContext extends MockContext { | |
| private String mPackageName; | |
| public StubContext(String packageName) { | |
| this.mPackageName = packageName; | |
| } | |
| @Override | |
| public String getPackageCodePath() { | |
| return mPackageName; | |
| } | |
| @Override | |
| public String getPackageName() { | |
| return mPackageName; | |
| } | |
| @Override | |
| public ClassLoader getClassLoader() { | |
| return getClass().getClassLoader(); | |
| } | |
| } | |
| private static class StubAndroidTestRunner extends AndroidTestRunner { | |
| private Test mTest; | |
| private boolean mRun; | |
| public boolean isRun() { | |
| return mRun; | |
| } | |
| public void setTest(Test test) { | |
| super.setTest(test); | |
| mTest = test; | |
| } | |
| public Test getTest() { | |
| return mTest; | |
| } | |
| public void runTest() { | |
| super.runTest(); | |
| mRun = true; | |
| } | |
| } | |
| /** | |
| * Empty test used for validation | |
| */ | |
| public static class PlaceHolderTest extends TestCase { | |
| public PlaceHolderTest() { | |
| super("testPlaceHolder"); | |
| } | |
| public void testPlaceHolder() throws Exception { | |
| } | |
| } | |
| /** | |
| * Empty test used for validation | |
| */ | |
| public static class PlaceHolderTest2 extends TestCase { | |
| public PlaceHolderTest2() { | |
| super("testPlaceHolder2"); | |
| } | |
| public void testPlaceHolder2() throws Exception { | |
| } | |
| } | |
| /** | |
| * Annotated test used for validation. | |
| */ | |
| public static class AnnotationTest extends TestCase { | |
| public void testNotAnnotated() throws Exception { | |
| } | |
| @FlakyTest | |
| public void testAnnotated() throws Exception { | |
| } | |
| } | |
| } |