org.scalatest.FixtureTestSuite.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 import org.scalatest._ import OutcomeOf.outcomeOf import org.scalactic._ /** * The base trait for ScalaTest's synchronous testing styles that accept a fixture * object passed into tests. This trait defines a *
Pending. This is * also true whenwithFixture
lifecycle method that takes as its parameter a test function * that accepts a fixture object and returns anOutcome
. * ** The abstract
* *withFixture
method add by this trait has the * following signature: ** def withFixture(test: OneArgTest): Outcome ** * Theapply
method of test function interface, *OneArgTest
, also returnsOutcome
: * * ** // In trait OneArgTest: * def apply(fixture: FixtureParam): Outcome ** ** Because the result of a test is an
Outcome
, when the test function returns, the test body must have determined an outcome already. It * will already be one ofSucceeded
,Failed
,Canceled
, orwithFixture(OneArgTest)
returns: because the result type ofwithFixture(OneArgTest)
isOutcome
, * the test has by definition already finished execution. * * ** The recommended way to ensure cleanup is performed after a test body finishes execution is * to use a
* *try
-finally
clause. * Usingtry
-finally
will ensure that cleanup will occur whether * the test function completes abruptly by throwing a suite-aborting exception, or returns * normally yielding anOutcome
. Note that the only situation in which a test function * will complete abruptly with an exception is if the test body throws a suite-aborting exception. * Any other exception will be caught and reported as either aFailed
,Canceled
, * orPending
. ** To enable the stacking of traits that define
* *withFixture(NoArgTest)
, it is a good idea to let *withFixture(NoArgTest)
invoke the test function instead of invoking the test * function directly. To do so, you'll need to convert theOneArgTest
to aNoArgTest
. You can do that by passing * the fixture object to thetoNoArgTest
method ofOneArgTest
. In other words, instead of * writing “test(theFixture)
”, you'd delegate responsibility for * invoking the test function to thewithFixture(NoArgTest)
method of the same instance by writing: ** withFixture(test.toNoArgTest(theFixture)) ** ** The
* *withFixture
method is designed to be stacked, and to enable this, you should always call thesuper
implementation * ofwithFixture
, and let it invoke the test function rather than invoking the test function directly. In other words, instead of writing * “test(...)
”, you should write “super.withFixture(test)
”. Thus, the recommended * structure of awithFixture
implementation that performs cleanup looks like this: ** // Your implementation * type FixtureParam = String * * override def withFixture(test: OneArgTest) = { * // Perform setup here * val theFixture = "hello" * try { * withFixture(test.toNoArgTest(theFixture)) // Invoke the test function * } finally { * // Perform cleanup here * } * } ** ** If you have no cleanup to perform, you can write
* *withFixture
like this instead: ** // Your implementation * type FixtureParam = String * * override def withFixture(test: NoArgTest) = { * // Perform setup here * val theFixture = "hello" * withFixture(test.toNoArgTest(theFixture)) // Invoke the test function * } ** ** If you want to perform an action only for certain outcomes, you can use * a pattern match. * For example, if you want to perform an action if a test fails, you'd * match on
* *Failed
, like this: ** // Your implementation * type FixtureParam = String * * override def withFixture(test: NoArgTest) = { * * // Perform setup here * val theFixture = "hello" * * val outcome = withFixture(test.toNoArgTest(theFixture)) // Invoke the test function * * outcome match { * case failed: Failed => * // perform action that you want to occur * // only if a test fails here * failed * case other => other * } * } ** ** If you want to change the outcome in some way in
* *withFixture
, you can also * use a pattern match. * For example, if a particular exception intermittently causes a test to fail, and can * transform those failures into cancelations, like this: ** // Your implementation * type FixtureParam = String * * override def withFixture(test: NoArgTest) = { * * val theFixture = "hello" * * withFixture(test.toNoArgTest(theFixture)) match { * case Failed(ex: ParticularException) => * Canceled("Muting flicker", ex) * case other => other * } * } **/ trait FixtureTestSuite extends org.scalatest.FixtureSuite with org.scalatest.TestSuite { thisTestSuite => /** * A test function taking a fixture parameter and returning anOutcome
. * ** For more detail and examples, see the * documentation for trait
*/ protected trait OneArgTest extends (FixtureParam => Outcome) with TestData { thisOneArgTest => /** * Runs the test, using the passedfixture.FlatSpec
. *FixtureParam
. * * @param fixture theFixtureParam
* @return an instance ofOutcome
*/ def apply(fixture: FixtureParam): Outcome /** * Convert thisOneArgTest
to aNoArgTest
whose *name
andconfigMap
methods return the same values * as thisOneArgTest
, and whoseapply
method invokes * thisOneArgTest
's apply method, * passing in the givenfixture
. * ** This method makes it easier to invoke the
* *withFixture
method * that takes aNoArgTest
. For example, if aFixtureSuite
* mixes inSeveredStackTraces
, it will inherit an implementation * ofwithFixture(NoArgTest)
provided by *SeveredStackTraces
that implements the stack trace severing * behavior. If theFixtureSuite
does not delegate to that *withFixture(NoArgTest)
method, the stack trace severing behavior * will not happen. Here's how that might look in aFixtureSuite
* whoseFixtureParam
isStringBuilder
: ** def withFixture(test: OneArgTest) = { * withFixture(test.toNoArgTest(new StringBuilder)) * } ** ** Invoking this method has no side effect. It just returns a
* * @param fixture theNoArgTest
whose *apply
method invokesapply
on thisOneArgTest
, passing * in theFixtureParam
passed totoNoArgTest
. *FixtureParam
* @return an new instance ofNoArgTest
*/ def toNoArgTest(fixture: FixtureParam) = new NoArgTest { val name = thisOneArgTest.name val configMap = thisOneArgTest.configMap def apply(): Outcome = { thisOneArgTest(fixture) } val scopes = thisOneArgTest.scopes val text = thisOneArgTest.text val tags = thisOneArgTest.tags val pos = thisOneArgTest.pos } } /** * Companion object forOneArgTest
that provides factory method to create newOneArgTest
* instance by passing in aOneArgTest
and aFixtureParam
=>Outcome
function. */ object OneArgTest { /** * Create newOneArgTest
instance. * * @param test aOneArgTest
* @param f aFixtureParam
=>Outcome
function * @return a new instance ofOneArgTest
, which will call the passedf
function in itsapply
method */ def apply(test: OneArgTest)(f: FixtureParam => Outcome): OneArgTest = { new OneArgTest { def apply(fixture: FixtureParam): Outcome = { f(fixture) } val text: String = test.text val configMap: ConfigMap = test.configMap val scopes: collection.immutable.IndexedSeq[String] = test.scopes val name: String = test.name val tags: Set[String] = test.tags val pos: Option[source.Position] = test.pos } } } /** * Run the passed test function with a fixture created by this method. * ** This method should create the fixture object needed by the tests of the * current suite, invoke the test function (passing in the fixture object), * and if needed, perform any clean up needed after the test completes. * For more detail and examples, see the main documentation for this trait. *
* * @param test theOneArgTest
to invoke, passing in a fixture * @return an instance ofOutcome
*/ protected def withFixture(test: OneArgTest): Outcome private[scalatest] class TestFunAndConfigMap(val name: String, test: FixtureParam => Any, val configMap: ConfigMap) extends OneArgTest { def apply(fixture: FixtureParam): Outcome = { outcomeOf { test(fixture) } } private val testData = testDataFor(name, configMap) val scopes = testData.scopes val text = testData.text val tags = testData.tags val pos = testData.pos } private[scalatest] class FixturelessTestFunAndConfigMap(override val name: String, test: () => Any, override val configMap: ConfigMap) extends NoArgTest { def apply(): Outcome = { outcomeOf { test() } } private val testData = testDataFor(name, configMap) val scopes = testData.scopes val text = testData.text val tags = testData.tags val pos = testData.pos } }