RegressionTestRunner.java :  » Mobile » jinjector » com » google » test » jinjector » Java Open Source

Java Open Source » Mobile » jinjector 
jinjector » com » google » test » jinjector » RegressionTestRunner.java
/* Copyright 2008 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 *    
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.test.jinjector;

import java.util.Enumeration;

import j2meunit.framework.*;
import j2meunit.textui.TestRunner;
import j2meunit.util.StringUtil;

/**
 * Starting point class for regression tests. 
 * 
 * <p> When instantiated this class starts its own thread 
 * and sequentially executes tests. 
 * 
 * <p>Each tests will be executed inside its own thread (they all 
 * implement {@link Runnable}). 
 * 
 * <p> The playback thread terminates when all tests have been executed and 
 * the results have been printed.
 * 
 * @author Michele Sama
 */
public class RegressionTestRunner extends TestRunner implements Runnable {

  /**
   * If the tests are run automatically, e.g. as part of a continuous build, 
   * the overall result of the tests can be detected by parsing the standard 
   * output for either of the following strings (FAIL, PASS). 
   */
  public static final String FAIL = "===FAIL===";
  
  /**
   * @see #FAIL
   */
  public static final String PASS = "===PASS===";
  
  /**
   * The test suite that this runner will execute. 
   */
  protected Test suite;
  
  /**
   * The test result used to contain test results during the execution. 
   */
  protected TestResult result;
  
  /**
   * Instance of the strategy to be used to display results on screen.
   */
  private final ResultDisplayerStrategy displayStrategy;
  
  /**
   * Specify if this test runner is being executed.
   * 
   * <p>This is necessary to make assertions on the actual execution status of 
   * this test base. 
   */ 
  private boolean executing = false;

  /**
   * Creates a play back thread with the specified {@link TestSuite}.
   * 
   * @param test The {@link TestSuite} that this test runner is
   *    going to reproduce.
   */
  public RegressionTestRunner(AssistedTestCase test) {
    this(test, null);
    // Do NOT invoke start() here!
  }
  
  /**
   * Creates a play back thread with the specified {@link TestSuite}.
   * 
   * @param test The {@link TestSuite} that this test runner is
   *    going to reproduce.
   * @param strategy The {@link ResultDisplayerStrategy} which will be used to 
   *    display results on screen. It can be <code>null</code>.   
   */
  public RegressionTestRunner(AssistedTestCase test, 
      ResultDisplayerStrategy strategy) {
    suite = test.suite();
    displayStrategy = strategy;
    // Do NOT invoke start() here!
  }
  
  /**
   * Starts the test into a separate thread.
   * 
   * <p> Please note that this cannot be invoked inside the constructor because
   * all the derived runner needs to specify additional parameters which have
   * to be set before the Thread starts. If this method was called inside the 
   * constructor the derived class would have invoked <code>super()</code>
   * and it would have generated a synchronization issue. 
   */
  public void start() {
      Thread th = new Thread(this, "RegressionTestRunner");
      th.start();
  }
  
  /**
   * Display tests results on screen.
   * 
   * <p> Derived classes should assign {@link #displayStrategy} properly, and 
   * it will be automatically invoked.
   */
  private final void displayResult() {
    if (displayStrategy != null) {
      displayStrategy.displayResult(result);
    }
  }
  
  /**
   * Runs all the tests sequentially, then write a full log and display 
   * the results on screen.
   * 
   * <p> Please note that when this thread is started the application should be
   * fully loaded. However this is application dependent and each regression 
   * test in its {@link TestCase#setup()} should make it sure that the 
   * application is ready to receive commands.
   * 
   * <p> The partial test result is printed to help in detecting the failure.
   * 
   * @see java.lang.Runnable#run()
   */
  public void run() {
    try {
      executing = true;
      doRun(suite);    
      //output list
      displayResult();
    } catch (Throwable t) {
      fWriter.println("General FAILURE!\n" +
          "This should not be happening and it is a general failure " +
          "not a bug in the application under test.\n" +
          "Possible causes are:\n" +
          "1) the emulator (or device) has run out of memory;\n" +
          "2) there is a bug in the instrumented code\n" +
          "3) there is a problem in the class path\n" +
          "4) The test suite contains tests which require a specific runner.");
      t.printStackTrace();
      print(result);
    } finally {
      executing = false;
    }
  }

  /**
   * Query if the regression tests still executing.
   *  
   * @return <code>true</code> if the play back is still in execution.
   */
  public boolean isExecuting() {
    return executing;
  }

  /**
   * Overrides the super method to prevent {@link System#exit(int)} from 
   * being invoked.
   * 
   * @param test The {@link Test} to run.
   * @see j2meunit.textui.TestRunner#doRun(j2meunit.framework.Test)
   */
  protected void doRun(Test test) {
    result = createTestResult();
    result.addListener(this);

    long startTime = System.currentTimeMillis();
    try {
      suite.run(result);
    } finally {
      long endTime = System.currentTimeMillis();
      long runTime = endTime - startTime;
      fWriter.println();
      fWriter.println("Time: " + StringUtil.elapsedTimeAsString(runTime));
      print(result);
      fWriter.println();
    }
  }

  /**
   * Overrides the super method by printing the stack trace.
   * 
   * @param testResult The {@link TestResult} on which tests have been executed.
   * @see TestRunner#printErrors(TestResult)
   */
  public void printErrors(TestResult testResult) {
    if (testResult.errorCount() != 0) {
        if (testResult.errorCount() == 1) {
            fWriter.println("There was 1 error:");
        } else {
            fWriter.println("There were " + 
                testResult.errorCount() + " errors:");
        }
        printErrorsOrFaults(testResult.errors());
    }
  }

  /**
   * Overrides the super method by printing the stack trace.
   * 
   * @param testResult The {@link TestResult} on which tests have been executed.
   * @see TestRunner#printFailures(TestResult)
   */
  public void printFailures(TestResult testResult) {
    if (testResult.failureCount() != 0) {
        if (testResult.failureCount() == 1) {
            fWriter.println("There was 1 failure:");
        } else {
            fWriter.println("There were " + 
                testResult.failureCount() +" failures:");
        }
        printErrorsOrFaults(testResult.failures());
    }
  }
  
  /**
   * Prints on the print writer contained in the super class (which prints on 
   * the standard output) a full error report for each failed test or for 
   * each error.
   * 
   * @param e An {@link Enumeration} containing a list of errors or faults.
   */
  protected void printErrorsOrFaults(Enumeration e) {
    int i = 1;
    for (; e.hasMoreElements(); i++) {
        TestFailure failure = (TestFailure) e.nextElement();
        fWriter.println(i + ") " + failure.failedTest());
        fWriter.println(failure.thrownException().getMessage());
        failure.thrownException().printStackTrace();
    }
  }

  /**
   * Print the overall header of the test.
   * 
   * <P> The string {@link #FAIL} must be printed in the standard output 
   * in order to allow the continuous build to realize that the test failed.
   * 
   * @see j2meunit.textui.TestRunner#printHeader(j2meunit.framework.TestResult)
   */
  public void printHeader(TestResult testResult) {
    if (testResult.wasSuccessful()) {
        fWriter.println();
        fWriter.print(PASS);
        fWriter.println(" (" + testResult.runCount() + " tests)");
    } else {
        fWriter.println();
        fWriter.println(FAIL);
        fWriter.println("Test Results:");
        fWriter.println("Run: " + testResult.runCount() + " Failures: " +
            testResult.failureCount() + " Errors: " +
            testResult.errorCount());
    }
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.