blob: 30876d0974f79e1129684bd471f07feddc5edb8f [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.test;
18
19import android.app.Instrumentation;
20import android.content.Context;
Jack Wangff1df692009-08-26 17:19:13 -070021import android.os.PerformanceCollector.PerformanceResultsWriter;
22
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import com.google.android.collect.Lists;
24import junit.framework.Test;
25import junit.framework.TestCase;
26import junit.framework.TestListener;
27import junit.framework.TestResult;
28import junit.framework.TestSuite;
29import junit.runner.BaseTestRunner;
30
Brian Muramatsu87571b72012-04-03 11:46:56 -070031import java.lang.reflect.Constructor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import java.lang.reflect.InvocationTargetException;
33import java.util.List;
34
35public 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;
Jack Wangff1df692009-08-26 17:19:13 -070045 private PerformanceResultsWriter mPerfWriter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046
47 @SuppressWarnings("unchecked")
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
60 public void setTest(Test test) {
61 setTest(test, test.getClass());
62 }
63
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
73 public void clearTestListeners() {
74 mTestListeners.clear();
75 }
76
77 public void addTestListener(TestListener testListener) {
78 if (testListener != null) {
79 mTestListeners.add(testListener);
80 }
81 }
82
83 @SuppressWarnings("unchecked")
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
93 private TestCase buildSingleTestMethod(Class testClass, String testMethodName) {
94 try {
Brian Muramatsu87571b72012-04-03 11:46:56 -070095 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
109 private TestCase newSingleTestMethod(Class testClass, String testMethodName,
110 Constructor constructor, Object... args) {
111 try {
112 TestCase testCase = (TestCase) constructor.newInstance(args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 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());
Brian Muramatsu87571b72012-04-03 11:46:56 -0700119 } 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());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 return null;
125 }
126
127 private boolean shouldRunSingleTestMethod(String testMethodName,
128 Class<? extends Test> testClass) {
129 return testMethodName != null && TestCase.class.isAssignableFrom(testClass);
130 }
131
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
151 protected TestResult createTestResult() {
152 if (mSkipExecution) {
153 return new NoExecTestResult();
154 }
155 return new TestResult();
156 }
Jack Wang4f414bd2009-11-06 20:53:47 -0800157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 void setSkipExecution(boolean skip) {
159 mSkipExecution = skip;
160 }
161
162 public List<TestCase> getTestCases() {
163 return mTestCases;
164 }
165
166 public String getTestClassName() {
167 return mTestClassName;
168 }
169
170 public TestResult getTestResult() {
171 return mTestResult;
172 }
173
174 public void runTest() {
175 runTest(createTestResult());
176 }
177
178 public void runTest(TestResult testResult) {
179 mTestResult = testResult;
180
181 for (TestListener testListener : mTestListeners) {
182 mTestResult.addListener(testListener);
183 }
184
Jack Wanga8db0a42009-08-17 14:19:52 -0700185 Context testContext = mInstrumentation == null ? mContext : mInstrumentation.getContext();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 for (TestCase testCase : mTestCases) {
Dmitri Plotnikov44a29dd2009-08-03 14:27:20 -0700187 setContextIfAndroidTestCase(testCase, mContext, testContext);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 setInstrumentationIfInstrumentationTestCase(testCase, mInstrumentation);
Jack Wang4f414bd2009-11-06 20:53:47 -0800189 setPerformanceWriterIfPerformanceCollectorTestCase(testCase, mPerfWriter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 testCase.run(mTestResult);
191 }
192 }
193
Dmitri Plotnikov44a29dd2009-08-03 14:27:20 -0700194 private void setContextIfAndroidTestCase(Test test, Context context, Context testContext) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 if (AndroidTestCase.class.isAssignableFrom(test.getClass())) {
196 ((AndroidTestCase) test).setContext(context);
Dmitri Plotnikov44a29dd2009-08-03 14:27:20 -0700197 ((AndroidTestCase) test).setTestContext(testContext);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 }
199 }
200
201 public void setContext(Context context) {
202 mContext = context;
203 }
204
205 private void setInstrumentationIfInstrumentationTestCase(
206 Test test, Instrumentation instrumentation) {
207 if (InstrumentationTestCase.class.isAssignableFrom(test.getClass())) {
Jack Wang7aba54b2009-08-20 19:20:54 -0700208 ((InstrumentationTestCase) test).injectInstrumentation(instrumentation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 }
210 }
211
Jack Wang4f414bd2009-11-06 20:53:47 -0800212 private void setPerformanceWriterIfPerformanceCollectorTestCase(
Jack Wangff1df692009-08-26 17:19:13 -0700213 Test test, PerformanceResultsWriter writer) {
Jack Wang4f414bd2009-11-06 20:53:47 -0800214 if (PerformanceCollectorTestCase.class.isAssignableFrom(test.getClass())) {
215 ((PerformanceCollectorTestCase) test).setPerformanceResultsWriter(writer);
Jack Wangff1df692009-08-26 17:19:13 -0700216 }
217 }
218
Jack Wang7aba54b2009-08-20 19:20:54 -0700219 public void setInstrumentation(Instrumentation instrumentation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 mInstrumentation = instrumentation;
221 }
222
Jack Wang7aba54b2009-08-20 19:20:54 -0700223 /**
224 * @deprecated Incorrect spelling,
225 * use {@link #setInstrumentation(android.app.Instrumentation)} instead.
226 */
227 @Deprecated
228 public void setInstrumentaiton(Instrumentation instrumentation) {
229 setInstrumentation(instrumentation);
230 }
231
Jack Wangff1df692009-08-26 17:19:13 -0700232 /**
233 * {@hide} Pending approval for public API.
234 */
235 public void setPerformanceResultsWriter(PerformanceResultsWriter writer) {
236 mPerfWriter = writer;
237 }
238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 @Override
240 protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
241 return mContext.getClassLoader().loadClass(suiteClassName);
242 }
243
244 public void testStarted(String testName) {
245 }
246
247 public void testEnded(String testName) {
248 }
249
250 public void testFailed(int status, Test test, Throwable t) {
251 }
252
253 protected void runFailed(String message) {
254 throw new RuntimeException(message);
255 }
256}