001    package junit.textui;
002    
003    
004    import java.io.PrintStream;
005    
006    import junit.framework.Test;
007    import junit.framework.TestCase;
008    import junit.framework.TestResult;
009    import junit.framework.TestSuite;
010    import junit.runner.BaseTestRunner;
011    import junit.runner.Version;
012    
013    /**
014     * A command line based tool to run tests.
015     * <pre>
016     * java junit.textui.TestRunner [-wait] TestCaseClass
017     * </pre>
018     * <p>
019     * TestRunner expects the name of a TestCase class as argument.
020     * If this class defines a static <code>suite</code> method it
021     * will be invoked and the returned test is run. Otherwise all
022     * the methods starting with "test" having no arguments are run.
023     * <p>
024     * When the wait command line argument is given TestRunner
025     * waits until the users types RETURN.
026     * <p>
027     * TestRunner prints a trace as the tests are executed followed by a
028     * summary at the end.
029     */
030    public class TestRunner extends BaseTestRunner {
031        private ResultPrinter fPrinter;
032    
033        public static final int SUCCESS_EXIT = 0;
034        public static final int FAILURE_EXIT = 1;
035        public static final int EXCEPTION_EXIT = 2;
036    
037        /**
038         * Constructs a TestRunner.
039         */
040        public TestRunner() {
041            this(System.out);
042        }
043    
044        /**
045         * Constructs a TestRunner using the given stream for all the output
046         */
047        public TestRunner(PrintStream writer) {
048            this(new ResultPrinter(writer));
049        }
050    
051        /**
052         * Constructs a TestRunner using the given ResultPrinter all the output
053         */
054        public TestRunner(ResultPrinter printer) {
055            fPrinter = printer;
056        }
057    
058        /**
059         * Runs a suite extracted from a TestCase subclass.
060         */
061        static public void run(Class<? extends TestCase> testClass) {
062            run(new TestSuite(testClass));
063        }
064    
065        /**
066         * Runs a single test and collects its results.
067         * This method can be used to start a test run
068         * from your program.
069         * <pre>
070         * public static void main (String[] args) {
071         *    test.textui.TestRunner.run(suite());
072         * }
073         * </pre>
074         */
075        static public TestResult run(Test test) {
076            TestRunner runner = new TestRunner();
077            return runner.doRun(test);
078        }
079    
080        /**
081         * Runs a single test and waits until the user
082         * types RETURN.
083         */
084        static public void runAndWait(Test suite) {
085            TestRunner aTestRunner = new TestRunner();
086            aTestRunner.doRun(suite, true);
087        }
088    
089        @Override
090        public void testFailed(int status, Test test, Throwable e) {
091        }
092    
093        @Override
094        public void testStarted(String testName) {
095        }
096    
097        @Override
098        public void testEnded(String testName) {
099        }
100    
101        /**
102         * Creates the TestResult to be used for the test run.
103         */
104        protected TestResult createTestResult() {
105            return new TestResult();
106        }
107    
108        public TestResult doRun(Test test) {
109            return doRun(test, false);
110        }
111    
112        public TestResult doRun(Test suite, boolean wait) {
113            TestResult result = createTestResult();
114            result.addListener(fPrinter);
115            long startTime = System.currentTimeMillis();
116            suite.run(result);
117            long endTime = System.currentTimeMillis();
118            long runTime = endTime - startTime;
119            fPrinter.print(result, runTime);
120    
121            pause(wait);
122            return result;
123        }
124    
125        protected void pause(boolean wait) {
126            if (!wait) return;
127            fPrinter.printWaitPrompt();
128            try {
129                System.in.read();
130            } catch (Exception e) {
131            }
132        }
133    
134        public static void main(String[] args) {
135            TestRunner aTestRunner = new TestRunner();
136            try {
137                TestResult r = aTestRunner.start(args);
138                if (!r.wasSuccessful()) {
139                    System.exit(FAILURE_EXIT);
140                }
141                System.exit(SUCCESS_EXIT);
142            } catch (Exception e) {
143                System.err.println(e.getMessage());
144                System.exit(EXCEPTION_EXIT);
145            }
146        }
147    
148        /**
149         * Starts a test run. Analyzes the command line arguments and runs the given
150         * test suite.
151         */
152        public TestResult start(String[] args) throws Exception {
153            String testCase = "";
154            String method = "";
155            boolean wait = false;
156    
157            for (int i = 0; i < args.length; i++) {
158                if (args[i].equals("-wait")) {
159                    wait = true;
160                } else if (args[i].equals("-c")) {
161                    testCase = extractClassName(args[++i]);
162                } else if (args[i].equals("-m")) {
163                    String arg = args[++i];
164                    int lastIndex = arg.lastIndexOf('.');
165                    testCase = arg.substring(0, lastIndex);
166                    method = arg.substring(lastIndex + 1);
167                } else if (args[i].equals("-v")) {
168                    System.err.println("JUnit " + Version.id() + " by Kent Beck and Erich Gamma");
169                } else {
170                    testCase = args[i];
171                }
172            }
173    
174            if (testCase.equals("")) {
175                throw new Exception("Usage: TestRunner [-wait] testCaseName, where name is the name of the TestCase class");
176            }
177    
178            try {
179                if (!method.equals("")) {
180                    return runSingleMethod(testCase, method, wait);
181                }
182                Test suite = getTest(testCase);
183                return doRun(suite, wait);
184            } catch (Exception e) {
185                throw new Exception("Could not create and run test suite: " + e);
186            }
187        }
188    
189        protected TestResult runSingleMethod(String testCase, String method, boolean wait) throws Exception {
190            Class<? extends TestCase> testClass = loadSuiteClass(testCase).asSubclass(TestCase.class);
191            Test test = TestSuite.createTest(testClass, method);
192            return doRun(test, wait);
193        }
194    
195        @Override
196        protected void runFailed(String message) {
197            System.err.println(message);
198            System.exit(FAILURE_EXIT);
199        }
200    
201        public void setPrinter(ResultPrinter printer) {
202            fPrinter = printer;
203        }
204    
205    
206    }