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

org.specs.specification.SpecificationStructure.scala Maven / Gradle / Ivy

There is a newer version: 1.4.3
Show newest version
package org.specs.specification
import org.specs.matcher.MatcherUtils._
import org.specs.SpecUtils._

/** 
 * This trait provides a structure to a specification.
* A specification is composed of:
    *
  • sub specifications or *
  • systems under tests (suts) *
  • examples which are components of systems under tests *
  • sub-examples which are components of examples

* * A specification is also given a description which is formed from its class name by default * but which can be also overriden

* * A specification can be composed of other specifications:
* "A complex specification".isSpecifiedBy(spec1, spec2)
* or declare("A complex specification").isSpecifiedBy(spec1, spec2) *

* A system under test can be created from a string with an implicit definition using should:
* "my system under test" should {}
* Alternatively, it could be created with: * specify("my system under test").should {} *

* Sub-examples can be created by declaring them inside the current example:

 * def otherExample = "this is a shared example" in { "this assertion" must notBeEmpty }       
 *       
 * "behave like other examples" in {
 *  otherExample      
 * } 
* Sub-examples are usually used to share examples across specifications (see the Stack example in test/scala/scala/specs/sample) *

* A SpecificationStructure also implements an ExampleLifeCycle trait * allowing subclasses to refine the behaviour of the specification before/after an example and before/after * a test inside an example. This is used to plug setup/teardown behaviour at the sut level and to plug * mock expectations checking when a specification is using the Mocker trait: mySpec extends Specification with Mocker */ trait SpecificationStructure extends ExampleLifeCycle { /** description of the specification */ var description = createDescription(getClass.getName) /** name of the specification */ var name = createDescription(getClass.getName) /** * @return a description from the class name, taking the last name which doesn't contain a $ or a number. * For example: com.pack1.MyClass$1$ will:

    *
  • split on $ and reverse: [1, com.pack1.MyClass] *
  • drop the every element which is an integer -> [com.pack1.MyClass] *
  • take the first element: com.pack1.MyClass *
  • split on . and reverse: [MyClass, pack1, com] *
  • take the last element: MyClass
*/ def createDescription(s: String) = s. split("\\$").reverse. dropWhile(isInteger(_))(0). split("\\."). reverse.toList(0) /** specifications contained by the current specification. An empty list by default */ var subSpecifications: List[Specification] = Nil /** this declares that a specification is composed of other specifications */ def isSpecifiedBy(specifications: Specification*) = { this.description = this.name + " is specified by" subSpecifications = subSpecifications:::specifications.toList } /** alias for isSpecifiedBy */ def areSpecifiedBy(specifications: Specification*) = { this.description = this.name + " are specified by" subSpecifications = subSpecifications:::specifications.toList } /** * implicit definition allowing to declare a composition inside the current specification: * "A complex specification".isSpecifiedBy(spec1, spec2) */ implicit def declare(d: String): SpecificationStructure = { name = d; this } /** list of systems under test */ var suts : List[Sut] = Nil /** * implicit definition allowing to declare a new system under test described by a string desc
* Usage: "my system under test" should {}
* Alternatively, it could be created with: * specify("my system under test").should {} */ implicit def specify(desc: String): Sut = { suts = suts:::List(new Sut(desc, this)) if (this.isSequential) suts.last.setSequential suts.last } /** utility method to track the last sut being currently defined, in order to be able to add examples to it */ protected[this] def currentSut = if (!suts.isEmpty) suts.last else specify("The system") /** * implicit definition allowing to declare a new example described by a string desc
* Usage: "return 0 when asked for (0+0)" in {...}
* Alternatively, it could be created with: * forExample("return 0 when asked for (0+0)").in {...} */ implicit def forExample(desc: String): Example = { val newExample = new Example(desc, currentSut) exampleContainer.addExample(newExample) newExample } /** * utility method to track the last example list being currently defined.
* It is either the list of examples associated with the current sut, or * the list of subexamples of the current example being defined */ protected[this] def exampleContainer: Any {def addExample(e: Example)} = { example match { case Some(e) => e case None => currentSut } } } /** * This abstract trait is used to represent how examples should be executed:
    *
  • sequentially or not ("not" is the default) *
  • with functions being executed before / after the example *
  • with functions being executed before / after the example tests *
*/ trait ExampleLifeCycle { protected var sequential = false def isSequential = sequential def setSequential = sequential = true protected[this] var example: Option[Example] = None def beforeExample(ex: Example) = {} def beforeTest(ex: Example)= {} def afterTest(ex: Example) = {} def executeTest(ex: Example, t: =>Any) = {example = Some(ex); t} def afterExample(ex: Example) = { example = None } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy