org.scalatest.fixture.MultipleFixtureWordSpec.scala Maven / Gradle / Ivy
/*
* Copyright 2001-2009 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.fixture
import org.scalatest._
/**
* A sister trait to org.scalatest.WordSpec
that can pass multiple types of fixture objects into its tests.
*
*
* This trait behaves similarly to trait org.scalatest.WordSpec
, except that tests may take a fixture object, and unlike
* a FixtureWordSpec
, different tests may take different types of fixtures. This trait extends FixtureWordSpec
* and mixes in ConfigMapFixture
, which defines the Fixture
type to be the configMap
's
* type (Map[String, Any]
) and defines the withFixture
method to simply pass the configMap
* to the test function. To write tests that take fixtures of types other than Fixture
(i.e.,
* Map[String, Any]
), you can define implicit conversions from a function of type (
<the fixture type>) => Unit
* to a function of type (FixtureParam) => Unit
. Each implicit conversion method serves as the with-fixture method for that type.
*
*
*
* Subclasses of this trait must, therefore, do two things differently from a plain old org.scalatest.WordSpec
:
*
*
*
* - define implicit
with<type>Fixture
methods
* - write tests that take the different fixture types for which you've defined implicit conversion methods (You can also define tests that don't take a
Fixture
.)
*
*
*
* Here's an example that has two fixture types, String
and List[Int]
:
*
*
*
* import org.scalatest.fixture.MultipleFixtureWordSpec
*
* class MyWordSpec extends MultipleFixtureWordSpec {
*
* // A test that takes a String fixture
* implicit def withStringFixture(testFunction: String => Unit): FixtureParam => Unit =
* testFunction("howdy")
*
* // The "with-fixture" method for tests that take a List[Int] fixture
* implicit def withListFixture(testFunction: List[Int] => Unit): FixtureParam => Unit =
* configMap => testFunction(List(configMap.size))
*
* "Tests in a MultipleFixtureWordSpec" should {
*
* // A test that takes a String fixture
* "take a string fixture" in { (s: String) =>
* assert(s === "howdy")
* }
*
* // A test that takes a List[Int] fixture
* "take a list fixture" in { (list: List[Int]) =>
* assert(list.size === 1)
* }
*
* // A test that takes no fixture
* "take no fixture" in { () =>
* assert(1 === 1)
* }
* }
* }
*
*
*
* The first method in this class, withStringFixture
, is the implicit conversion function for tests that take a fixture
* of type String
. In this contrived example, the hard-coded string "howdy"
is passed into the test:
*
*
*
* implicit def withStringFixture(testFunction: String => Unit): FixtureParam => Unit =
* testFunction("howdy")
*
*
*
* Although the result type of this implicit conversion method is FixtureParam => Unit
, if a fixture doesn't need anything
* from the configMap
, you can leave off the configMap =>
at the beginning of the result function. The
* reason this works is that MultipleFixtureWordSpec
inherits an implicit conversion from a by-name parameter to
* FixtureParam => Unit
from supertrait FixtureWordSpec
. This implicit conversion is used to enable
* tests that take no fixture (such as the one named takes no fixture
in this example) to be included in the
* same class as tests that take type Fixture
. That same implicit conversion is used here to allow you to leave off
* the configMap =>
except when you actually need something from the configMap
. By leaving it off, you
* indicte to readers of the code that this fixture doesn't require anything from the configMap
.
*
*
*
* The next method in this class, withListFixture
, is the implicit conversion function for tests that take a
* fixture of type List[Int]
. In this contrived example, a List[Int]
that contains one element, the
* size of the configMap
, is passed to the test function. Because the fixture uses the configMap
,
* it has an explicit configMap =>
parameter at the beginning of the result. (Remember, the Fixture
* type is defined to be Map[String, Any]
, the type of the configMap
, in supertrait ConfigMapFixture
.
*
*
*
* Following the implicit conversion methods are the test declarations. One test is written to take the String
fixture:
*
*
*
* "take a string fixture" in { (s: String) =>
* assert(s === "howdy")
* }
*
*
*
* What happens at compile time is that because the Fixture
type is Map[String, Any]
, the test
method
* should be passed a function from type (Map[String, Any]) => Unit
, or using the type alias, (FixtureParam) => Unit
. Passing
* a function of type String => Unit
as is attempted here is a type error. Thus the compiler will look around for an implicit
* conversion that will fix the type error, and will find the withStringFixture
method. Because this is the only implicit
* conversion that fixes the type error, it will apply it, effectively generating this code:
*
*
*
* // after the implicit withStringFixture method is applied by the compiler
* "take a string fixture" in {
* withStringFixture { (s: String) =>
* assert(s === "howdy")
* }
* }
*
*
*
* After passing the (String) => Unit
function to withStringFixture
, the result will be of
* type (FixtureParam) => Unit
, which the test
method expects.
*
*
*
* The next test is written to take the List[Int]
fixture:
*
*
*
* "take a list fixture" in { (list: List[Int]) =>
* assert(list.size === 1)
* }
*
*
*
* The compiler will apply the withListFixture
implicit conversion in this case, effectively generating the following
* code:
*
*
*
* "take a list fixture" in {
* withListFixture { (list: List[Int]) =>
* assert(list.size === 1)
* }
* }
*
*
*
* Note that in a FixtureWordSpec
, you need to specify the type of the fixture explicitly so the compiler knows
* the type to convert from. So you must, for example, write:
*
*
*
* "take a list fixture" in { (list: List[Int]) =>
* assert(list.size === 1)
* }
*
*
*
* The following attempt will fail to compile:
*
*
*
* // won't compile, because list is inferred to be of type FixtureParam
* "take a list fixture" in { list =>
* assert(list.size === 1)
* }
*
*
* @author Bill Venners
*/
trait MultipleFixtureWordSpec extends FixtureWordSpec with ConfigMapFixture