| /* |
| * 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 { |
| } |
| } |
| } |