1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.test; 18 19 import android.app.Instrumentation; 20 import android.content.Context; 21 import android.os.PerformanceCollector.PerformanceResultsWriter; 22 23 import com.google.android.collect.Lists; 24 import junit.framework.Test; 25 import junit.framework.TestCase; 26 import junit.framework.TestListener; 27 import junit.framework.TestResult; 28 import junit.framework.TestSuite; 29 import junit.runner.BaseTestRunner; 30 31 import java.lang.reflect.Constructor; 32 import java.lang.reflect.InvocationTargetException; 33 import java.util.List; 34 35 public class AndroidTestRunner extends BaseTestRunner { 36 37 private TestResult mTestResult; 38 private String mTestClassName; 39 private List<TestCase> mTestCases; 40 private Context mContext; 41 private boolean mSkipExecution = false; 42 43 private List<TestListener> mTestListeners = Lists.newArrayList(); 44 private Instrumentation mInstrumentation; 45 private PerformanceResultsWriter mPerfWriter; 46 47 @SuppressWarnings("unchecked") setTestClassName(String testClassName, String testMethodName)48 public void setTestClassName(String testClassName, String testMethodName) { 49 Class testClass = loadTestClass(testClassName); 50 51 if (shouldRunSingleTestMethod(testMethodName, testClass)) { 52 TestCase testCase = buildSingleTestMethod(testClass, testMethodName); 53 mTestCases = Lists.newArrayList(testCase); 54 mTestClassName = testClass.getSimpleName(); 55 } else { 56 setTest(getTest(testClass), testClass); 57 } 58 } 59 setTest(Test test)60 public void setTest(Test test) { 61 setTest(test, test.getClass()); 62 } 63 setTest(Test test, Class<? extends Test> testClass)64 private void setTest(Test test, Class<? extends Test> testClass) { 65 mTestCases = (List<TestCase>) TestCaseUtil.getTests(test, true); 66 if (TestSuite.class.isAssignableFrom(testClass)) { 67 mTestClassName = TestCaseUtil.getTestName(test); 68 } else { 69 mTestClassName = testClass.getSimpleName(); 70 } 71 } 72 clearTestListeners()73 public void clearTestListeners() { 74 mTestListeners.clear(); 75 } 76 addTestListener(TestListener testListener)77 public void addTestListener(TestListener testListener) { 78 if (testListener != null) { 79 mTestListeners.add(testListener); 80 } 81 } 82 83 @SuppressWarnings("unchecked") loadTestClass(String testClassName)84 private Class<? extends Test> loadTestClass(String testClassName) { 85 try { 86 return (Class<? extends Test>) mContext.getClassLoader().loadClass(testClassName); 87 } catch (ClassNotFoundException e) { 88 runFailed("Could not find test class. Class: " + testClassName); 89 } 90 return null; 91 } 92 buildSingleTestMethod(Class testClass, String testMethodName)93 private TestCase buildSingleTestMethod(Class testClass, String testMethodName) { 94 try { 95 Constructor c = testClass.getConstructor(); 96 return newSingleTestMethod(testClass, testMethodName, c); 97 } catch (NoSuchMethodException e) { 98 } 99 100 try { 101 Constructor c = testClass.getConstructor(String.class); 102 return newSingleTestMethod(testClass, testMethodName, c, testMethodName); 103 } catch (NoSuchMethodException e) { 104 } 105 106 return null; 107 } 108 newSingleTestMethod(Class testClass, String testMethodName, Constructor constructor, Object... args)109 private TestCase newSingleTestMethod(Class testClass, String testMethodName, 110 Constructor constructor, Object... args) { 111 try { 112 TestCase testCase = (TestCase) constructor.newInstance(args); 113 testCase.setName(testMethodName); 114 return testCase; 115 } catch (IllegalAccessException e) { 116 runFailed("Could not access test class. Class: " + testClass.getName()); 117 } catch (InstantiationException e) { 118 runFailed("Could not instantiate test class. Class: " + testClass.getName()); 119 } catch (IllegalArgumentException e) { 120 runFailed("Illegal argument passed to constructor. Class: " + testClass.getName()); 121 } catch (InvocationTargetException e) { 122 runFailed("Constructor thew an exception. Class: " + testClass.getName()); 123 } 124 return null; 125 } 126 shouldRunSingleTestMethod(String testMethodName, Class<? extends Test> testClass)127 private boolean shouldRunSingleTestMethod(String testMethodName, 128 Class<? extends Test> testClass) { 129 return testMethodName != null && TestCase.class.isAssignableFrom(testClass); 130 } 131 getTest(Class clazz)132 private Test getTest(Class clazz) { 133 if (TestSuiteProvider.class.isAssignableFrom(clazz)) { 134 try { 135 TestSuiteProvider testSuiteProvider = 136 (TestSuiteProvider) clazz.getConstructor().newInstance(); 137 return testSuiteProvider.getTestSuite(); 138 } catch (InstantiationException e) { 139 runFailed("Could not instantiate test suite provider. Class: " + clazz.getName()); 140 } catch (IllegalAccessException e) { 141 runFailed("Illegal access of test suite provider. Class: " + clazz.getName()); 142 } catch (InvocationTargetException e) { 143 runFailed("Invocation exception test suite provider. Class: " + clazz.getName()); 144 } catch (NoSuchMethodException e) { 145 runFailed("No such method on test suite provider. Class: " + clazz.getName()); 146 } 147 } 148 return getTest(clazz.getName()); 149 } 150 createTestResult()151 protected TestResult createTestResult() { 152 if (mSkipExecution) { 153 return new NoExecTestResult(); 154 } 155 return new TestResult(); 156 } 157 setSkipExecution(boolean skip)158 void setSkipExecution(boolean skip) { 159 mSkipExecution = skip; 160 } 161 getTestCases()162 public List<TestCase> getTestCases() { 163 return mTestCases; 164 } 165 getTestClassName()166 public String getTestClassName() { 167 return mTestClassName; 168 } 169 getTestResult()170 public TestResult getTestResult() { 171 return mTestResult; 172 } 173 runTest()174 public void runTest() { 175 runTest(createTestResult()); 176 } 177 runTest(TestResult testResult)178 public void runTest(TestResult testResult) { 179 mTestResult = testResult; 180 181 for (TestListener testListener : mTestListeners) { 182 mTestResult.addListener(testListener); 183 } 184 185 Context testContext = mInstrumentation == null ? mContext : mInstrumentation.getContext(); 186 for (TestCase testCase : mTestCases) { 187 setContextIfAndroidTestCase(testCase, mContext, testContext); 188 setInstrumentationIfInstrumentationTestCase(testCase, mInstrumentation); 189 setPerformanceWriterIfPerformanceCollectorTestCase(testCase, mPerfWriter); 190 testCase.run(mTestResult); 191 } 192 } 193 setContextIfAndroidTestCase(Test test, Context context, Context testContext)194 private void setContextIfAndroidTestCase(Test test, Context context, Context testContext) { 195 if (AndroidTestCase.class.isAssignableFrom(test.getClass())) { 196 ((AndroidTestCase) test).setContext(context); 197 ((AndroidTestCase) test).setTestContext(testContext); 198 } 199 } 200 setContext(Context context)201 public void setContext(Context context) { 202 mContext = context; 203 } 204 setInstrumentationIfInstrumentationTestCase( Test test, Instrumentation instrumentation)205 private void setInstrumentationIfInstrumentationTestCase( 206 Test test, Instrumentation instrumentation) { 207 if (InstrumentationTestCase.class.isAssignableFrom(test.getClass())) { 208 ((InstrumentationTestCase) test).injectInstrumentation(instrumentation); 209 } 210 } 211 setPerformanceWriterIfPerformanceCollectorTestCase( Test test, PerformanceResultsWriter writer)212 private void setPerformanceWriterIfPerformanceCollectorTestCase( 213 Test test, PerformanceResultsWriter writer) { 214 if (PerformanceCollectorTestCase.class.isAssignableFrom(test.getClass())) { 215 ((PerformanceCollectorTestCase) test).setPerformanceResultsWriter(writer); 216 } 217 } 218 setInstrumentation(Instrumentation instrumentation)219 public void setInstrumentation(Instrumentation instrumentation) { 220 mInstrumentation = instrumentation; 221 } 222 223 /** 224 * @deprecated Incorrect spelling, 225 * use {@link #setInstrumentation(android.app.Instrumentation)} instead. 226 */ 227 @Deprecated setInstrumentaiton(Instrumentation instrumentation)228 public void setInstrumentaiton(Instrumentation instrumentation) { 229 setInstrumentation(instrumentation); 230 } 231 232 /** 233 * {@hide} Pending approval for public API. 234 */ setPerformanceResultsWriter(PerformanceResultsWriter writer)235 public void setPerformanceResultsWriter(PerformanceResultsWriter writer) { 236 mPerfWriter = writer; 237 } 238 239 @Override loadSuiteClass(String suiteClassName)240 protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException { 241 return mContext.getClassLoader().loadClass(suiteClassName); 242 } 243 testStarted(String testName)244 public void testStarted(String testName) { 245 } 246 testEnded(String testName)247 public void testEnded(String testName) { 248 } 249 testFailed(int status, Test test, Throwable t)250 public void testFailed(int status, Test test, Throwable t) { 251 } 252 runFailed(String message)253 protected void runFailed(String message) { 254 throw new RuntimeException(message); 255 } 256 } 257