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 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")
     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 {
     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 
    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 
    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     }
    157 
    158     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 
    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 
    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 
    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())) {
    208             ((InstrumentationTestCase) test).injectInstrumentation(instrumentation);
    209         }
    210     }
    211 
    212     private void setPerformanceWriterIfPerformanceCollectorTestCase(
    213             Test test, PerformanceResultsWriter writer) {
    214         if (PerformanceCollectorTestCase.class.isAssignableFrom(test.getClass())) {
    215             ((PerformanceCollectorTestCase) test).setPerformanceResultsWriter(writer);
    216         }
    217     }
    218 
    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
    228     public void setInstrumentaiton(Instrumentation instrumentation) {
    229         setInstrumentation(instrumentation);
    230     }
    231 
    232     /**
    233      * {@hide} Pending approval for public API.
    234      */
    235     public void setPerformanceResultsWriter(PerformanceResultsWriter writer) {
    236         mPerfWriter = writer;
    237     }
    238 
    239     @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 }
    257