org.scalatest.BeforeAndAfterEach.scala Maven / Gradle / Ivy
/*
* Copyright 2001-2013 Artima, 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 org.scalatest
/**
* Stackable trait that can be mixed into suites that need code executed before and/or after running each test.
*
*
* Recommended Usage:
* Use trait BeforeAndAfterEach
when you want to stack traits that perform side-effects before and/or after tests, rather
* than at the beginning or end of tests.
* Note: For more insight into where BeforeAndAfterEach
fits into the big picture, see the
* Shared fixtures section in the documentation for your chosen style trait.
*
*
*
* A test fixture is composed of the objects and other artifacts (files, sockets, database
* connections, etc.) tests use to do their work.
* When multiple tests need to work with the same fixtures, it is important to try and avoid
* duplicating the fixture code across those tests. The more code duplication you have in your
* tests, the greater drag the tests will have on refactoring the actual production code, and
* the slower your compile will likely be.
* Trait BeforeAndAfterEach
offers one way to eliminate such code duplication:
* a beforeEach
method that will be run before each test (like JUnit's setUp
),
* and an afterEach
method that will be run after (like JUnit's tearDown
).
*
*
*
* Here's an example:
*
*
*
* package org.scalatest.examples.flatspec.composingbeforeandaftereach
*
* import org.scalatest._
* import collection.mutable.ListBuffer
*
* trait Builder extends BeforeAndAfterEach { this: Suite =>
*
* val builder = new StringBuilder
*
* override def beforeEach() {
* builder.append("ScalaTest is ")
* super.beforeEach() // To be stackable, must call super.beforeEach
* }
*
* override def afterEach() {
* try {
* super.afterEach() // To be stackable, must call super.afterEach
* }
* finally {
* builder.clear()
* }
* }
* }
*
* trait Buffer extends BeforeAndAfterEach { this: Suite =>
*
* val buffer = new ListBuffer[String]
*
* override def afterEach() {
* try {
* super.afterEach() // To be stackable, must call super.afterEach
* }
* finally {
* buffer.clear()
* }
* }
* }
*
* class ExampleSpec extends FlatSpec with Builder with Buffer {
*
* "Testing" should "be easy" in {
* builder.append("easy!")
* assert(builder.toString === "ScalaTest is easy!")
* assert(buffer.isEmpty)
* buffer += "sweet"
* }
*
* it should "be fun" in {
* builder.append("fun!")
* assert(builder.toString === "ScalaTest is fun!")
* assert(buffer.isEmpty)
* buffer += "clear"
* }
* }
*
*
*
* To get the same ordering as withFixture
, place your super.beforeEach
call at the end of each
* beforeEach
method, and the super.afterEach
call at the beginning of each afterEach
* method, as shown in the previous example. It is a good idea to invoke super.afterEach
in a try
* block and perform cleanup in a finally
clause, as shown in the previous example, because this ensures the
* cleanup code is performed even if super.afterEach
throws an exception.
*
*
*
* The main advantage of BeforeAndAfterEach
over BeforeAndAfter
is that BeforeAndAfterEach
.
* enables trait stacking.
* The main disadvantage of BeforeAndAfterEach
compared to BeforeAndAfter
is that BeforeAndAfterEach
* requires more boilerplate. If you don't need trait stacking, use BeforeAndAfter
instead
* of BeforeAndAfterEach
.
* If you want to make use of test data (the test name, config map, etc.) in your beforeEach
* or afterEach
method, use trait BeforeAndAfterEachTestData
instead.
*
*
* @author Bill Venners
*/
trait BeforeAndAfterEach extends SuiteMixin {
this: Suite =>
/**
* Defines a method to be run before each of this suite's tests.
*
*
* This trait's implementation of runTest
invokes this method before
* invoking super.runTest
. Thus this method can be used to set up a test
* fixture needed by each test, before each test begins execution.
*
*
*
* This trait's implementation of this method does nothing.
*
*/
protected def beforeEach() = ()
/**
* Defines a method to be run after each of this suite's tests.
*
*
* This trait's implementation
* of runTest
invokes this method after invoking super.runTest
.
* Thus this method can be used to tear down a test fixture
* needed by each test, after each test completes execution.
*
*
*
* This trait's implementation of this method does nothing.
*
*/
protected def afterEach() = ()
/**
* Runs a test surrounded by calls to beforeEach()
and afterEach()
.
*
*
* This trait's implementation of this method ("this method") invokes
* beforeEach()
* before running each test and afterEach()
* after running each test. It runs each test by invoking super.runTest
, passing along
* the two parameters passed to it.
*
*
*
* If any invocation of beforeEach()
completes abruptly with an exception, this
* method will complete abruptly with the same exception, however, before doing so, it will
* invoke afterEach()
.
* If beforeEach()
returns normally, but the subsequent call to
* super.runTest
completes abruptly with an exception, this method
* will complete abruptly with the same exception, however, before doing so, it will
* invoke afterEach()
.
* If afterEach()
completes abruptly with an exception, this
* method will nevertheless complete abruptly with an exception previously thrown by either
* beforeEach()
or super.runTest
.
* If both beforeEach()
and super.runTest
return normally, but
* afterEach()
completes abruptly with an exception, this method will complete
* abruptly with the exception thrown by afterEach()
.
*
*
*
* The reason this method invokes afterEach()
even if beforeEach()
or
* super.runTest
throws an exception is to reduce the chance that a resource
* acquired by beforeEach()
or super.runTest
prior to completing
* abruptly with the exception is not cleaned up and therefore leaked.
*
*
* @param testName the name of one test to run.
* @param args the Args
for this run
* @return a Status
object that indicates when the test started by this method has completed, and whether or not it failed .
*/
/*
abstract protected override def runTest(testName: String, args: Args): Status = {
var thrownException: Option[Throwable] = None
if (!args.runTestInNewInstance) beforeEach()
try {
super.runTest(testName, args)
}
catch {
case e: Exception =>
thrownException = Some(e)
FailedStatus
}
finally {
try {
if (!args.runTestInNewInstance) afterEach() // Make sure that afterEach is called even if runTest completes abruptly.
thrownException match {
case Some(e) => throw e
case None =>
}
}
catch {
case laterException: Exception =>
thrownException match { // If both run and afterAll throw an exception, report the test exception
case Some(earlierException) => throw earlierException
case None => throw laterException
}
}
}
}
*/
abstract protected override def runTest(testName: String, args: Args): Status = {
var thrownException: Option[Throwable] = None
val runTestStatus: Status =
try {
if (!args.runTestInNewInstance) beforeEach()
super.runTest(testName, args)
}
catch {
case e: Throwable if !Suite.anExceptionThatShouldCauseAnAbort(e) =>
thrownException = Some(e)
FailedStatus
}
// And if the exception should cause an abort, abort the afterEach too.
try {
val statusToReturn: Status =
if (!args.runTestInNewInstance) {
runTestStatus withAfterEffect {
try {
afterEach()
}
catch {
case e: Throwable if !Suite.anExceptionThatShouldCauseAnAbort(e) && thrownException.isDefined =>
// We will swallow an exception thrown from afterEach if it is not test-aborting
// and an exception was already thrown by beforeEach or test itself.
}
} // Make sure that afterEach is called even if (beforeEach or runTest) completes abruptly.
}
else
runTestStatus
thrownException match {
case Some(e) => throw e
case None =>
}
statusToReturn
}
catch {
case laterException: Exception =>
thrownException match {
// If both (beforeEach or runTest) and afterEach throw an exception, throw the
// earlier exception and swallow the later exception. The reason we swallow
// the later exception rather than printing it is that it may be noisy because
// it is caused by the beforeEach failing in the first place. Our goal with
// this approach is to minimize the chances that a finite non-memory resource
// acquired in beforeEach is not cleaned up in afterEach.
case Some(earlierException) => throw earlierException
case None => throw laterException
}
}
}
}