All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.specs.runner.JUnit.scala Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2007-2009 Eric Torreborre 
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of
 * the Software. Neither the name of specs nor the names of its contributors may be used to endorse or promote
 * products derived from this software without specific prior written permission.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */
package org.specs.runner

import org.specs._
import org.specs.specification._
import _root_.junit.framework._
import _root_.org.junit.runner._
import org.specs.collection.JavaCollectionsConversion._
import org.specs.util.Stacktraces
import org.specs.execute._
import org.specs.util.Property

/**
 * The strategy for running Specifications with JUnit is as follow:

* * -the specifications are used to create JUnit3 TestSuite and TestCase objects * -however, since TestSuite is not an interface, a JUnitSuite trait is used to represent it (and the JUnitSuite uses a TestSuite internally to hold the tests) * -a specification is represented as a JUnitSuite * -a system under test (sus) is represented as an ExamplesTestSuite <: JUnitSuite * -an example is represented as an ExampleTestCase <: TestCase * * Then, the JUnitSuite which implements the junit.framework.Test interface can be run using * a custom JUnit4 annotation: JUnitSuiteRunner * * This JUnitSuite trait encapsulates a JUnit3 TestSuite to allow it being seen as a trait and not a class * The suite is initialized once whenever some information is required, like getName, or countTestCases */ @RunWith(classOf[JUnitSuiteRunner]) trait JUnitSuite extends Test { /** embedded JUnit3 TestSuite object */ val testSuite = new TestSuite /**this variable is set to true if the suite has been initialized */ private var initialized = false /**the init method is called before any "getter" method is called. Then it initializes the object if it hasn't been done before */ def init = if (!initialized) { initialize; initialized = true } /**the initialize method should be provided to build the testSuite object by adding nested suites and test cases */ def initialize /**run the embedded suite */ def run(result: TestResult) = { init testSuite.run(result) } /**@return the name of the embedded suite */ def getName = { init testSuite.getName } /**set the name of the embedded suite */ def setName(n: java.lang.String) = testSuite.setName(n) /** add a new test to the embedded suite */ def addTest(t: Test) = testSuite.addTest(t) /** @return the tests of the embedded suite (suites and test cases) */ def tests: List[Test] = { init enumerationToList(testSuite.tests) } /** @return the number of tests of the embedded suite (suites and test cases) */ def countTestCases: Int = { init tests.size } /**@return the test cases of the embedded suite */ def testCases: List[Test] = { init for (tc <- tests; if (tc.isInstanceOf[TestCase])) yield tc.asInstanceOf[TestCase] } /**@return the test suites of the embedded suite */ def suites = { init for (ts <- tests; if (ts.isInstanceOf[JUnitSuite] || ts.isInstanceOf[TestSuite])) yield ts.asInstanceOf[Test] } } /** * Extension of a JUnitSuite initializing the suite with one or more specifications */ trait JUnit extends JUnitSuite with Reporter { def initialize = { if (filteredSpecs.size > 1) setName(this.getClass.getName.replaceAll("\\$", "")) else setName(filteredSpecs.headOption.map(_.description).getOrElse("no specs")) filteredSpecs foreach { specification => specification.subSpecifications.foreach{s: Specification => addTest(new JUnit3(s))} specification.systems foreach { sus => val examples = if (!planOnly() && sus.hasOwnFailureOrErrors) sus :: sus.examples else sus.examples addTest(new ExamplesTestSuite(sus.description + " " + sus.verb, examples, sus.ownSkipped.headOption)) } } } } /** * Concrete class providing specifications to be used as a JUnitSuite * @deprecated use JUnit4 instead as the JUnitSuite class runs with a JUnit4 runner */ @RunWith(classOf[JUnitSuiteRunner]) class JUnit3(val specifications: Specification*) extends JUnit { val specs: Seq[Specification] = specifications } /** * Concrete class providing specifications to be used as a JUnitSuite */ @RunWith(classOf[JUnitSuiteRunner]) class JUnit4(val specifications: Specification*) extends JUnit { val specs: Seq[Specification] = specifications } /** * A ExamplesTestSuite is a JUnitSuite reporting the results of * a System under test (sus) as a list of examples, represented by ExampleTestCase objects. * If an example has subExamples, they won't be shown as sub tests because that would necessitate to * run the example during the initialization time. */ class ExamplesTestSuite(description: String, examples: Iterable[Examples], skipped: Option[Throwable]) extends JUnitSuite with Stacktraces { /**return true if the current test is executed with Maven */ lazy val isExecutedFromMaven = isExecutedFrom("org.apache.maven.surefire.Surefire.run") /** * create one TestCase per example */ def initialize = { setName(description) examples foreach { example => // if the test is run with Maven the sus description is added to the example description for a better // description in the console val exampleDescription = (if (isExecutedFromMaven) (description + " ") else "") + example.description if (JUnitOptions.planOnly() || example.examples.isEmpty) addTest(new ExampleTestCase(example, exampleDescription)) else addTest(new ExamplesTestSuite(exampleDescription, example.examples, None)) } } /** * runs the set of exemplesA ExamplesTestSuite is a JUnitSuite reporting the results of * a list of examples. If an example has subExamples, they are reported with a separate ExamplesTestSuite * If the list of examples is skipped (because the corresponding sus is skipped), then a SkippedAssertionError failure is sent * and the JUnitSuiteRunner will interpret this as an ignored test (this functionality wasn't available in JUnit3) */ override def run(result: TestResult) = { if (!JUnitOptions.planOnly()) skipped.map(e => result.addFailure(this, new SkippedAssertionError(e))) super.run(result) } } /** * A ExampleTestCase reports the result of an example

* It overrides the run method from junit.framework.TestCase * to add errors and failures to a junit.framework.TestResult object * * When possible, the description of the subexamples are added to their failures and skipped exceptions */ class ExampleTestCase(val example: Examples, description: String) extends TestCase(description.replaceAll("\n", " ")) { override def run(result: TestResult) = { if (JUnitOptions.planOnly() || example.ownSkipped.isEmpty) result.startTest(this) def report(ex: Examples, context: String) = { ex.ownFailures foreach { failure: FailureException => result.addFailure(this, new SpecAssertionFailedError(UserError(failure, context))) } ex.ownSkipped foreach { skipped: SkippedException => result.addFailure(this, new SkippedAssertionError(UserError(skipped, context))) } ex.ownErrors foreach { error: Throwable => result.addError(this, new SpecError(UserError(error, context))) } } if (!JUnitOptions.planOnly()) { report(example, "") example.examples foreach {subExample => report(subExample, subExample.description + " -> ")} } if (JUnitOptions.planOnly() || example.ownSkipped.isEmpty) result.endTest(this) } } case class UserError(t: Throwable, context: String) extends Throwable { setStackTrace(t.getStackTrace) override def getCause = t.getCause override def getMessage = { t match { case f: FailureException => context + t.getMessage case _ => t.getClass.getName + ": " + context + t.getMessage } } } /** * This class refines the AssertionFailedError from junit * and provides the stackTrace of an exception which occured during the specification execution */ class SpecAssertionFailedError(t: Throwable) extends AssertionFailedError(t.getMessage) { override def getStackTrace = t.getStackTrace override def getCause = t.getCause override def printStackTrace = t.printStackTrace override def printStackTrace(w: java.io.PrintStream) = t.printStackTrace(w) override def printStackTrace(w: java.io.PrintWriter) = t.printStackTrace(w) } /** * This class represents errors thrown in an example. It needs to be set as something * different from an AssertionFailedError so that tools like Ant can make the distinction between failures and errors */ class SpecError(t: Throwable) extends java.lang.Error(t.getMessage) { override def getStackTrace = t.getStackTrace override def getCause = t.getCause override def printStackTrace = t.printStackTrace override def printStackTrace(w: java.io.PrintStream) = t.printStackTrace(w) override def printStackTrace(w: java.io.PrintWriter) = t.printStackTrace(w) } class SkippedAssertionError(t: Throwable) extends SpecAssertionFailedError(t) /** * This trait allows to pass system options to Tests and TestSuites */ object JUnitOptions { val planOnly = Property(System.getProperty("plan") != null) }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy