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