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