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