TestLoader.java revision 53196f43b44ff02da07c243798168d7e5614ec34
1/*
2 * Copyright (C) 2012 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 com.android.test.runner;
18
19import android.util.Log;
20
21import org.junit.runner.Description;
22import org.junit.runner.notification.Failure;
23
24import java.io.PrintStream;
25import java.lang.reflect.Method;
26import java.util.ArrayList;
27import java.util.Collection;
28import java.util.List;
29
30/**
31 * A class for loading JUnit3 and JUnit4 test classes given a set of potential class names.
32 */
33public class TestLoader {
34
35    private static final String LOG_TAG = "TestLoader";
36
37    public static class LoadResults {
38        private final List<Class<?>> mLoadedClasses;
39        private final List<Failure> mMissingClasses;
40
41        LoadResults(List<Class<?>> loadedClasses, List<Failure> missingClasses) {
42            mMissingClasses = missingClasses;
43            mLoadedClasses = loadedClasses;
44        }
45
46        public List<Class<?>> getLoadedClasses() {
47            return mLoadedClasses;
48        }
49
50        public List<Failure> getLoadFailures() {
51            return mMissingClasses;
52        }
53    }
54
55    /**
56     * Loads the test classes from the given list of test names.
57     *
58     * @param classNames the {@link Collection} of class names to attempt to load
59     * @param writer the {@link PrintStream} to use to output error messages
60     * @return the {@link LoadResults} containing the test classes
61     */
62    public LoadResults loadTests(Collection<String> classNames, PrintStream writer) {
63        List<Class<?>> classes = new ArrayList<Class<?>>();
64        List<Failure> missingClasses = new ArrayList<Failure>();
65        for (String className : classNames) {
66            try {
67                Class<?> loadedClass = Class.forName(className);
68                if (isTestClass(loadedClass)) {
69                    classes.add(loadedClass);
70                }
71            } catch (ClassNotFoundException e) {
72                String errMsg = String.format("Could not find class: %s", className);
73                Log.e(LOG_TAG, errMsg);
74                writer.println(errMsg);
75                Description description = Description.createSuiteDescription(className);
76                Failure failure = new Failure(description, e);
77                missingClasses.add(failure);
78            }
79        }
80        return new LoadResults(classes, missingClasses);
81    }
82
83    /**
84     * Determines if given class is a valid test class.
85     *
86     * @param loadedClass
87     * @return <code>true</code> if loadedClass is a test
88     */
89    private boolean isTestClass(Class<?> loadedClass) {
90        // TODO: try to find upstream junit calls to replace these checks
91        if (junit.framework.Test.class.isAssignableFrom(loadedClass)) {
92            return true;
93        }
94        // TODO: look for a 'suite' method?
95        if (loadedClass.isAnnotationPresent(org.junit.runner.RunWith.class)) {
96            return true;
97        }
98        for (Method testMethod : loadedClass.getMethods()) {
99            if (testMethod.isAnnotationPresent(org.junit.Test.class)) {
100                return true;
101            }
102        }
103        Log.v(LOG_TAG, String.format("Skipping class %s: not a test", loadedClass.getName()));
104        return false;
105    }
106}
107