Implementation trait for class fixture.FeatureSpec
, which is
a sister class to org.scalatest.FeatureSpec
that can pass a
fixture object into its tests.
Implementation trait for class fixture.FlatSpec
, which is
a sister class to org.scalatest.FlatSpec
that can pass a
fixture object into its tests.
Implementation trait for class fixture.FlatSpec
, which is
a sister class to org.scalatest.FlatSpec
that can pass a
fixture object into its tests.
fixture.FlatSpec
is a class,
not a trait, to minimize compile time given there is a slight compiler
overhead to mixing in traits compared to extending classes. If you need
to mix the behavior of fixture.FlatSpec
into some other
class, you can use this trait instead, because class
fixture.FlatSpec
does nothing more than extend this trait and add a nice toString
implementation.
See the documentation of the class for a detailed
overview of fixture.FlatSpec
.
Implementation trait for class fixture.FreeSpec
, which is
a sister class to org.scalatest.FreeSpec
that can pass a
fixture object into its tests.
Implementation trait for class fixture.FreeSpec
, which is
a sister class to org.scalatest.FreeSpec
that can pass a
fixture object into its tests.
fixture.FreeSpec
is a class,
not a trait, to minimize compile time given there is a slight compiler
overhead to mixing in traits compared to extending classes. If you need
to mix the behavior of fixture.FreeSpec
into some other
class, you can use this trait instead, because class
fixture.FreeSpec
does nothing more than extend this trait and add a nice toString
implementation.
See the documentation of the class for a detailed
overview of fixture.FreeSpec
.
Implementation trait for class fixture.FunSpec
, which is
a sister class to org.scalatest.FunSpec
that can pass a
fixture object into its tests.
Implementation trait for class fixture.FunSpec
, which is
a sister class to org.scalatest.FunSpec
that can pass a
fixture object into its tests.
fixture.FunSpec
is a class,
not a trait, to minimize compile time given there is a slight compiler
overhead to mixing in traits compared to extending classes. If you need
to mix the behavior of fixture.FunSpec
into some other
class, you can use this trait instead, because class
fixture.FunSpec
does nothing more than extend this trait and add a nice toString
implementation.
See the documentation of the class for a detailed
overview of fixture.FunSpec
.
Implementation trait for class fixture.FunSuite
, which is
a sister class to org.scalatest.FunSuite
that can pass a
fixture object into its tests.
Implementation trait for class fixture.FunSuite
, which is
a sister class to org.scalatest.FunSuite
that can pass a
fixture object into its tests.
fixture.FunSuite
is a class,
not a trait, to minimize compile time given there is a slight compiler
overhead to mixing in traits compared to extending classes. If you need
to mix the behavior of fixture.FunSuite
into some other
class, you can use this trait instead, because class
fixture.FunSuite
does nothing more than extend this trait and add a nice toString
implementation.
See the documentation of the class for a detailed
overview of fixture.FunSuite
.
Implementation trait for class fixture.PropSpec
, which is
a sister class to org.scalatest.PropSpec
that can pass a
fixture object into its tests.
Implementation trait for class fixture.PropSpec
, which is
a sister class to org.scalatest.PropSpec
that can pass a
fixture object into its tests.
fixture.PropSpec
is a class,
not a trait, to minimize compile time given there is a slight compiler
overhead to mixing in traits compared to extending classes. If you need
to mix the behavior of fixture.PropSpec
into some other
class, you can use this trait instead, because class
fixture.PropSpec
does nothing more than extend this trait and add a nice toString
implementation.
See the documentation of the class for a detailed
overview of fixture.PropSpec
.
Implementation trait for class fixture.WordSpec
, which is
a sister class to org.scalatest.WordSpec
that can pass a
fixture object into its tests.
Implementation trait for class fixture.WordSpec
, which is
a sister class to org.scalatest.WordSpec
that can pass a
fixture object into its tests.
fixture.WordSpec
is a class,
not a trait, to minimize compile time given there is a slight compiler
overhead to mixing in traits compared to extending classes. If you need
to mix the behavior of fixture.WordSpec
into some other
class, you can use this trait instead, because class
fixture.WordSpec
does nothing more than extend this trait and add a nice toString
implementation.
See the documentation of the class for a detailed
overview of fixture.WordSpec
.
Trait that when mixed into a fixture.Suite
passes
the config map passed to runTest
as a fixture into each test.
Trait that when mixed into a fixture.Suite
passes
the config map passed to runTest
as a fixture into each test.
Here's an example in which tests just check to make sure "hello"
and "world"
are defined keys in the config map:
package org.scalatest.examples.fixture.configmapfixture import org.scalatest._ class ExampleSpec extends fixture.FlatSpec with fixture.ConfigMapFixture with ShouldMatchers { "The config map" should "contain hello" in { configMap => // Use the configMap passed to runTest in the test configMap should contain key "hello" } it should "contain world" in { configMap => configMap should contain key "world" } }
If you run this class without defining "hello"
and "world"
in the confg map, the tests will fail:
scala> new ExampleSpec execute ExampleSpec: The config map - should contain hello *** FAILED *** Map() did not contain key "hello" (:20) - should contain world *** FAILED *** Map() did not contain key "world" ( :24)
If you do define "hello"
and "world"
keys
in the confg map, the tests will success:
scala> new ExampleSpec execute (configMap = Map("hello" -> "hi", "world" -> "globe"))
ExampleSpec:
The config map
- should contain hello
- should contain world
A sister class to org.scalatest.FeatureSpec
that can pass a fixture object into its tests.
A sister class to org.scalatest.FeatureSpec
that can pass a fixture object into its tests.
Recommended Usage:
Use class fixture.FeatureSpec in situations for which FeatureSpec
would be a good choice, when all or most tests need the same fixture objects
that must be cleaned up afterwards. Note: fixture.FeatureSpec is intended for use in special situations, with class FeatureSpec used for general needs. For
more insight into where fixture.FeatureSpec fits in the big picture, see the withFixture(OneArgTest) subsection of the Shared fixtures section in the documentation for class FeatureSpec .
|
Class fixture.FeatureSpec
behaves similarly to class org.scalatest.FeatureSpec
, except that tests may have a
fixture parameter. The type of the
fixture parameter is defined by the abstract FixtureParam
type, which is a member of this class.
This trait also has an abstract withFixture
method. This withFixture
method
takes a OneArgTest
, which is a nested trait defined as a member of this class.
OneArgTest
has an apply
method that takes a FixtureParam
.
This apply
method is responsible for running a test.
This class's runTest
method delegates the actual running of each test to withFixture(OneArgTest)
, passing
in the test code to run via the OneArgTest
argument. The withFixture(OneArgTest)
method (abstract in this class) is responsible
for creating the fixture argument and passing it to the test function.
Subclasses of this class must, therefore, do three things differently from a plain old org.scalatest.FeatureSpec
:
FixtureParam
withFixture(OneArgTest)
methodIf the fixture you want to pass into your tests consists of multiple objects, you will need to combine them into one object to use this class. One good approach to passing multiple fixture objects is to encapsulate them in a case class. Here's an example:
case class FixtureParam(file: File, writer: FileWriter)
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 the OneArgTest
to a NoArgTest
. You can do that by passing
the fixture object to the toNoArgTest
method of OneArgTest
. In other words, instead of
writing “test(theFixture)
”, you'd delegate responsibility for
invoking the test function to the withFixture(NoArgTest)
method of the same instance by writing:
withFixture(test.toNoArgTest(theFixture))
Here's a complete example:
package org.scalatest.examples.featurespec.oneargtest import org.scalatest.fixture import java.io._ class ExampleSpec extends fixture.FeatureSpec { case class FixtureParam(file: File, writer: FileWriter) def withFixture(test: OneArgTest) = { // create the fixture val file = File.createTempFile("hello", "world") val writer = new FileWriter(file) val theFixture = FixtureParam(file, writer) try { writer.write("ScalaTest is designed to be ") // set up the fixture withFixture(test.toNoArgTest(theFixture)) // "loan" the fixture to the test } finally writer.close() // clean up the fixture } feature("Simplicity") { scenario("User needs to read test code written by others") { f => f.writer.write("encourage clear code!") f.writer.flush() assert(f.file.length === 49) } scenario("User needs to understand what the tests are doing") { f => f.writer.write("be easy to reason about!") f.writer.flush() assert(f.file.length === 52) } } }
If a test fails, the OneArgTest
function will result in a Failed wrapping the exception describing the failure.
To ensure clean up happens even if a test fails, you should invoke the test function from inside a try
block and do the cleanup in a
finally
clause, as shown in the previous example.
If multiple test classes need the same fixture, you can define the FixtureParam
and withFixture(OneArgTest)
implementations
in a trait, then mix that trait into the test classes that need it. For example, if your application requires a database and your integration tests
use that database, you will likely have many test classes that need a database fixture. You can create a "database fixture" trait that creates a
database with a unique name, passes the connector into the test, then removes the database once the test completes. This is shown in the following example:
package org.scalatest.examples.fixture.featurespec.sharing import java.util.concurrent.ConcurrentHashMap import org.scalatest.fixture import DbServer._ import java.util.UUID.randomUUID object DbServer { // Simulating a database server type Db = StringBuffer private val databases = new ConcurrentHashMap[String, Db] def createDb(name: String): Db = { val db = new StringBuffer databases.put(name, db) db } def removeDb(name: String) { databases.remove(name) } } trait DbFixture { this: fixture.Suite => type FixtureParam = Db // Allow clients to populate the database after // it is created def populateDb(db: Db) {} def withFixture(test: OneArgTest) { val dbName = randomUUID.toString val db = createDb(dbName) // create the fixture try { populateDb(db) // setup the fixture withFixture(test.toNoArgTest(db)) // "loan" the fixture to the test } finally removeDb(dbName) // clean up the fixture } } class ExampleSpec extends fixture.FeatureSpec with DbFixture { override def populateDb(db: Db) { // setup the fixture db.append("ScalaTest is designed to ") } feature("Simplicity") { scenario("User needs to read test code written by others") { db => db.append("encourage clear code!") assert(db.toString === "ScalaTest is designed to encourage clear code!") } scenario("User needs to understand what the tests are doing") { db => db.append("be easy to reason about!") assert(db.toString === "ScalaTest is designed to be easy to reason about!") } scenario("User needs to write tests") { () => val buf = new StringBuffer buf.append("ScalaTest is designed to be ") buf.append("easy to learn!") assert(buf.toString === "ScalaTest is designed to be easy to learn!") } } }
Often when you create fixtures in a trait like DbFixture
, you'll still need to enable individual test classes
to "setup" a newly created fixture before it gets passed into the tests. A good way to accomplish this is to pass the newly
created fixture into a setup method, like populateDb
in the previous example, before passing it to the test
function. Classes that need to perform such setup can override the method, as does ExampleSpec
.
If a test doesn't need the fixture, you can indicate that by providing a no-arg instead of a one-arg function, as is done in the
third test in the previous example, “Test code should be clear
”. In other words, instead of starting your function literal
with something like “db =>
”, you'd start it with “() =>
”. For such tests, runTest
will not invoke withFixture(OneArgTest)
. It will instead directly invoke withFixture(NoArgTest)
.
Both examples shown above demonstrate the technique of giving each test its own "fixture sandbox" to play in. When your fixtures
involve external side-effects, like creating files or databases, it is a good idea to give each file or database a unique name as is
done in these examples. This keeps tests completely isolated, allowing you to run them in parallel if desired. You could mix
ParallelTestExecution
into either of these ExampleSpec
classes, and the tests would run in parallel just fine.
Implementation trait for class fixture.FeatureSpec
, which is
a sister class to org.scalatest.FeatureSpec
that can pass a
fixture object into its tests.
Implementation trait for class fixture.FeatureSpec
, which is
a sister class to org.scalatest.FeatureSpec
that can pass a
fixture object into its tests.
fixture.FeatureSpec
is a class,
not a trait, to minimize compile time given there is a slight compiler
overhead to mixing in traits compared to extending classes. If you need
to mix the behavior of fixture.FeatureSpec
into some other
class, you can use this trait instead, because class
fixture.FeatureSpec
does nothing more than extend this trait and add a nice toString
implementation.
See the documentation of the class for a detailed
overview of fixture.FeatureSpec
.
A sister class to org.scalatest.FlatSpec
that can pass a fixture object into its tests.
A sister class to org.scalatest.FlatSpec
that can pass a fixture object into its tests.
Recommended Usage:
Use class fixture.FlatSpec in situations for which FlatSpec
would be a good choice, when all or most tests need the same fixture objects
that must be cleaned up afterwards. Note: fixture.FlatSpec is intended for use in special situations, with class FlatSpec used for general needs. For
more insight into where fixture.FlatSpec fits in the big picture, see the withFixture(OneArgTest) subsection of the Shared fixtures section in the documentation for class FlatSpec .
|
Class fixture.FlatSpec
behaves similarly to class org.scalatest.FlatSpec
, except that tests may have a
fixture parameter. The type of the
fixture parameter is defined by the abstract FixtureParam
type, which is a member of this class.
This class also contains an abstract withFixture
method. This withFixture
method
takes a OneArgTest
, which is a nested trait defined as a member of this class.
OneArgTest
has an apply
method that takes a FixtureParam
.
This apply
method is responsible for running a test.
This class's runTest
method delegates the actual running of each test to withFixture(OneArgTest)
, passing
in the test code to run via the OneArgTest
argument. The withFixture(OneArgTest)
method (abstract in this class) is responsible
for creating the fixture argument and passing it to the test function.
Subclasses of this class must, therefore, do three things differently from a plain old org.scalatest.FlatSpec
:
FixtureParam
withFixture(OneArgTest)
methodIf the fixture you want to pass into your tests consists of multiple objects, you will need to combine them into one object to use this class. One good approach to passing multiple fixture objects is to encapsulate them in a case class. Here's an example:
case class FixtureParam(file: File, writer: FileWriter)
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 the OneArgTest
to a NoArgTest
. You can do that by passing
the fixture object to the toNoArgTest
method of OneArgTest
. In other words, instead of
writing “test(theFixture)
”, you'd delegate responsibility for
invoking the test function to the withFixture(NoArgTest)
method of the same instance by writing:
withFixture(test.toNoArgTest(theFixture))
Here's a complete example:
package org.scalatest.examples.flatspec.oneargtest import org.scalatest.fixture import java.io._ class ExampleSpec extends fixture.FlatSpec { case class FixtureParam(file: File, writer: FileWriter) def withFixture(test: OneArgTest) = { // create the fixture val file = File.createTempFile("hello", "world") val writer = new FileWriter(file) val theFixture = FixtureParam(file, writer) try { writer.write("ScalaTest is ") // set up the fixture withFixture(test.toNoArgTest(theFixture)) // "loan" the fixture to the test } finally writer.close() // clean up the fixture } "Testing" should "be easy" in { f => f.writer.write("easy!") f.writer.flush() assert(f.file.length === 18) } it should "be fun" in { f => f.writer.write("fun!") f.writer.flush() assert(f.file.length === 17) } }
If a test fails because of an exception, the OneArgTest
function will result in a Failed wrapping the exception.
To ensure clean up happens even if an exception occurs, you should invoke the test function from inside a try
block and do the cleanup in a
finally
clause, as shown in the previous example.
If multiple test classes need the same fixture, you can define the FixtureParam
and withFixture(OneArgTest)
implementations
in a trait, then mix that trait into the test classes that need it. For example, if your application requires a database and your integration tests
use that database, you will likely have many test classes that need a database fixture. You can create a "database fixture" trait that creates a
database with a unique name, passes the connector into the test, then removes the database once the test completes. This is shown in the following example:
package org.scalatest.examples.fixture.flatspec.sharing import java.util.concurrent.ConcurrentHashMap import org.scalatest.fixture import DbServer._ import java.util.UUID.randomUUID object DbServer { // Simulating a database server type Db = StringBuffer private val databases = new ConcurrentHashMap[String, Db] def createDb(name: String): Db = { val db = new StringBuffer databases.put(name, db) db } def removeDb(name: String) { databases.remove(name) } } trait DbFixture { this: fixture.Suite => type FixtureParam = Db // Allow clients to populate the database after // it is created def populateDb(db: Db) {} def withFixture(test: OneArgTest) = { val dbName = randomUUID.toString val db = createDb(dbName) // create the fixture try { populateDb(db) // setup the fixture withFixture(test.toNoArgTest(db)) // "loan" the fixture to the test } finally removeDb(dbName) // clean up the fixture } } class ExampleSpec extends fixture.FlatSpec with DbFixture { override def populateDb(db: Db) { // setup the fixture db.append("ScalaTest is ") } "Testing" should "be easy" in { db => db.append("easy!") assert(db.toString === "ScalaTest is easy!") } it should "be fun" in { db => db.append("fun!") assert(db.toString === "ScalaTest is fun!") } // This test doesn't need a Db "Test code" should "be clear" in { () => val buf = new StringBuffer buf.append("ScalaTest code is ") buf.append("clear!") assert(buf.toString === "ScalaTest code is clear!") } }
Often when you create fixtures in a trait like DbFixture
, you'll still need to enable individual test classes
to "setup" a newly created fixture before it gets passed into the tests. A good way to accomplish this is to pass the newly
created fixture into a setup method, like populateDb
in the previous example, before passing it to the test
function. Classes that need to perform such setup can override the method, as does ExampleSpec
.
If a test doesn't need the fixture, you can indicate that by providing a no-arg instead of a one-arg function, as is done in the
third test in the previous example, “Test code should be clear
”. In other words, instead of starting your function literal
with something like “db =>
”, you'd start it with “() =>
”. For such tests, runTest
will not invoke withFixture(OneArgTest)
. It will instead directly invoke withFixture(NoArgTest)
.
Both examples shown above demonstrate the technique of giving each test its own "fixture sandbox" to play in. When your fixtures
involve external side-effects, like creating files or databases, it is a good idea to give each file or database a unique name as is
done in these examples. This keeps tests completely isolated, allowing you to run them in parallel if desired. You could mix
ParallelTestExecution
into either of these ExampleSpec
classes, and the tests would run in parallel just fine.
Implementation trait for class fixture.FlatSpec
, which is
a sister class to org.scalatest.FlatSpec
that can pass a
fixture object into its tests.
Implementation trait for class fixture.FlatSpec
, which is
a sister class to org.scalatest.FlatSpec
that can pass a
fixture object into its tests.
fixture.FlatSpec
is a class,
not a trait, to minimize compile time given there is a slight compiler
overhead to mixing in traits compared to extending classes. If you need
to mix the behavior of fixture.FlatSpec
into some other
class, you can use this trait instead, because class
fixture.FlatSpec
does nothing more than extend this trait and add a nice toString
implementation.
See the documentation of the class for a detailed
overview of fixture.FlatSpec
.
A sister class to org.scalatest.FreeSpec
that can pass a fixture object into its tests.
A sister class to org.scalatest.FreeSpec
that can pass a fixture object into its tests.
Recommended Usage:
Use class fixture.FreeSpec in situations for which FreeSpec
would be a good choice, when all or most tests need the same fixture objects
that must be cleaned up afterwards. Note: fixture.FreeSpec is intended for use in special situations, with class FreeSpec used for general needs. For
more insight into where fixture.FreeSpec fits in the big picture, see the withFixture(OneArgTest) subsection of the Shared fixtures section in the documentation for class FreeSpec .
|
Class fixture.FreeSpec
behaves similarly to class org.scalatest.FreeSpec
, except that tests may have a
fixture parameter. The type of the
fixture parameter is defined by the abstract FixtureParam
type, which is a member of this class.
This class also has an abstract withFixture
method. This withFixture
method
takes a OneArgTest
, which is a nested trait defined as a member of this class.
OneArgTest
has an apply
method that takes a FixtureParam
.
This apply
method is responsible for running a test.
This class's runTest
method delegates the actual running of each test to withFixture(OneArgTest)
, passing
in the test code to run via the OneArgTest
argument. The withFixture(OneArgTest)
method (abstract in this class) is responsible
for creating the fixture argument and passing it to the test function.
Subclasses of this class must, therefore, do three things differently from a plain old org.scalatest.FreeSpec
:
FixtureParam
withFixture(OneArgTest)
methodIf the fixture you want to pass into your tests consists of multiple objects, you will need to combine them into one object to use this class. One good approach to passing multiple fixture objects is to encapsulate them in a case class. Here's an example:
case class FixtureParam(file: File, writer: FileWriter)
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 the OneArgTest
to a NoArgTest
. You can do that by passing
the fixture object to the toNoArgTest
method of OneArgTest
. In other words, instead of
writing “test(theFixture)
”, you'd delegate responsibility for
invoking the test function to the withFixture(NoArgTest)
method of the same instance by writing:
withFixture(test.toNoArgTest(theFixture))
Here's a complete example:
package org.scalatest.examples.freespec.oneargtest import org.scalatest.fixture import java.io._ class ExampleSpec extends fixture.FreeSpec { case class FixtureParam(file: File, writer: FileWriter) def withFixture(test: OneArgTest) = { // create the fixture val file = File.createTempFile("hello", "world") val writer = new FileWriter(file) val theFixture = FixtureParam(file, writer) try { writer.write("ScalaTest is ") // set up the fixture withFixture(test.toNoArgTest(theFixture)) // "loan" the fixture to the test } finally writer.close() // clean up the fixture } "Testing" - { "should be easy" in { f => f.writer.write("easy!") f.writer.flush() assert(f.file.length === 18) } "should be fun" in { f => f.writer.write("fun!") f.writer.flush() assert(f.file.length === 17) } } }
If a test fails, the OneArgTest
function will result in a Failed wrapping the exception describing the failure.
To ensure clean up happens even if a test fails, you should invoke the test function from inside a try
block and do the cleanup in a
finally
clause, as shown in the previous example.
If multiple test classes need the same fixture, you can define the FixtureParam
and withFixture(OneArgTest)
implementations
in a trait, then mix that trait into the test classes that need it. For example, if your application requires a database and your integration tests
use that database, you will likely have many test classes that need a database fixture. You can create a "database fixture" trait that creates a
database with a unique name, passes the connector into the test, then removes the database once the test completes. This is shown in the following example:
package org.scalatest.examples.fixture.freespec.sharing import java.util.concurrent.ConcurrentHashMap import org.scalatest.fixture import DbServer._ import java.util.UUID.randomUUID object DbServer { // Simulating a database server type Db = StringBuffer private val databases = new ConcurrentHashMap[String, Db] def createDb(name: String): Db = { val db = new StringBuffer databases.put(name, db) db } def removeDb(name: String) { databases.remove(name) } } trait DbFixture { this: fixture.Suite => type FixtureParam = Db // Allow clients to populate the database after // it is created def populateDb(db: Db) {} def withFixture(test: OneArgTest) = { val dbName = randomUUID.toString val db = createDb(dbName) // create the fixture try { populateDb(db) // setup the fixture withFixture(test.toNoArgTest(db)) // "loan" the fixture to the test } finally removeDb(dbName) // clean up the fixture } } class ExampleSpec extends fixture.FreeSpec with DbFixture { override def populateDb(db: Db) { // setup the fixture db.append("ScalaTest is ") } "Testing" - { "should be easy" in { db => db.append("easy!") assert(db.toString === "ScalaTest is easy!") } "should be fun" in { db => db.append("fun!") assert(db.toString === "ScalaTest is fun!") } } // This test doesn't need a Db "Test code" - { "should be clear" in { () => val buf = new StringBuffer buf.append("ScalaTest code is ") buf.append("clear!") assert(buf.toString === "ScalaTest code is clear!") } } }
Often when you create fixtures in a trait like DbFixture
, you'll still need to enable individual test classes
to "setup" a newly created fixture before it gets passed into the tests. A good way to accomplish this is to pass the newly
created fixture into a setup method, like populateDb
in the previous example, before passing it to the test
function. Classes that need to perform such setup can override the method, as does ExampleSpec
.
If a test doesn't need the fixture, you can indicate that by providing a no-arg instead of a one-arg function, as is done in the
third test in the previous example, “Test code should be clear
”. In other words, instead of starting your function literal
with something like “db =>
”, you'd start it with “() =>
”. For such tests, runTest
will not invoke withFixture(OneArgTest)
. It will instead directly invoke withFixture(NoArgTest)
.
Both examples shown above demonstrate the technique of giving each test its own "fixture sandbox" to play in. When your fixtures
involve external side-effects, like creating files or databases, it is a good idea to give each file or database a unique name as is
done in these examples. This keeps tests completely isolated, allowing you to run them in parallel if desired. You could mix
ParallelTestExecution
into either of these ExampleSpec
classes, and the tests would run in parallel just fine.
Implementation trait for class fixture.FreeSpec
, which is
a sister class to org.scalatest.FreeSpec
that can pass a
fixture object into its tests.
Implementation trait for class fixture.FreeSpec
, which is
a sister class to org.scalatest.FreeSpec
that can pass a
fixture object into its tests.
fixture.FreeSpec
is a class,
not a trait, to minimize compile time given there is a slight compiler
overhead to mixing in traits compared to extending classes. If you need
to mix the behavior of fixture.FreeSpec
into some other
class, you can use this trait instead, because class
fixture.FreeSpec
does nothing more than extend this trait and add a nice toString
implementation.
See the documentation of the class for a detailed
overview of fixture.FreeSpec
.
A sister class to org.scalatest.FunSpec
that can pass a fixture object into its tests.
A sister class to org.scalatest.FunSpec
that can pass a fixture object into its tests.
Recommended Usage:
Use class fixture.FunSpec in situations for which FunSpec
would be a good choice, when all or most tests need the same fixture objects
that must be cleaned up afterwards. Note: fixture.FunSpec is intended for use in special situations, with class FunSpec used for general needs. For
more insight into where fixture.FunSpec fits in the big picture, see the withFixture(OneArgTest) subsection of the Shared fixtures section in the documentation for class FunSpec .
|
Class fixture.FunSpec
behaves similarly to class org.scalatest.FunSpec
, except that tests may have a
fixture parameter. The type of the
fixture parameter is defined by the abstract FixtureParam
type, which is a member of this class.
This class also contains an abstract withFixture
method. This withFixture
method
takes a OneArgTest
, which is a nested trait defined as a member of this class.
OneArgTest
has an apply
method that takes a FixtureParam
.
This apply
method is responsible for running a test.
This class's runTest
method delegates the actual running of each test to withFixture(OneArgTest)
, passing
in the test code to run via the OneArgTest
argument. The withFixture(OneArgTest)
method (abstract in this class) is responsible
for creating the fixture argument and passing it to the test function.
Subclasses of this class must, therefore, do three things differently from a plain old org.scalatest.FunSpec
:
FixtureParam
withFixture(OneArgTest)
methodIf the fixture you want to pass into your tests consists of multiple objects, you will need to combine them into one object to use this class. One good approach to passing multiple fixture objects is to encapsulate them in a case class. Here's an example:
case class FixtureParam(file: File, writer: FileWriter)
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 the OneArgTest
to a NoArgTest
. You can do that by passing
the fixture object to the toNoArgTest
method of OneArgTest
. In other words, instead of
writing “test(theFixture)
”, you'd delegate responsibility for
invoking the test function to the withFixture(NoArgTest)
method of the same instance by writing:
withFixture(test.toNoArgTest(theFixture))
Here's a complete example:
package org.scalatest.examples.funspec.oneargtest import org.scalatest.fixture import java.io._ class ExampleSpec extends fixture.FunSpec { case class FixtureParam(file: File, writer: FileWriter) def withFixture(test: OneArgTest) = { // create the fixture val file = File.createTempFile("hello", "world") val writer = new FileWriter(file) val theFixture = FixtureParam(file, writer) try { writer.write("ScalaTest is ") // set up the fixture withFixture(test.toNoArgTest(theFixture)) // "loan" the fixture to the test } finally writer.close() // clean up the fixture } describe("Testing") { it("should be easy") { f => f.writer.write("easy!") f.writer.flush() assert(f.file.length === 18) } it("should be fun") { f => f.writer.write("fun!") f.writer.flush() assert(f.file.length === 17) } } }
If a test fails, the OneArgTest
function will result in a Failed wrapping the exception describing the failure.
To ensure clean up happens even if a test fails, you should invoke the test function from inside a try
block and do the cleanup in a
finally
clause, as shown in the previous example.
If multiple test classes need the same fixture, you can define the FixtureParam
and withFixture(OneArgTest)
implementations
in a trait, then mix that trait into the test classes that need it. For example, if your application requires a database and your integration tests
use that database, you will likely have many test classes that need a database fixture. You can create a "database fixture" trait that creates a
database with a unique name, passes the connector into the test, then removes the database once the test completes. This is shown in the following example:
package org.scalatest.examples.fixture.funspec.sharing import java.util.concurrent.ConcurrentHashMap import org.scalatest.fixture import DbServer._ import java.util.UUID.randomUUID object DbServer { // Simulating a database server type Db = StringBuffer private val databases = new ConcurrentHashMap[String, Db] def createDb(name: String): Db = { val db = new StringBuffer databases.put(name, db) db } def removeDb(name: String) { databases.remove(name) } } trait DbFixture { this: fixture.Suite => type FixtureParam = Db // Allow clients to populate the database after // it is created def populateDb(db: Db) {} def withFixture(test: OneArgTest) = { val dbName = randomUUID.toString val db = createDb(dbName) // create the fixture try { populateDb(db) // setup the fixture withFixture(test.toNoArgTest(db)) // "loan" the fixture to the test } finally removeDb(dbName) // clean up the fixture } } class ExampleSpec extends fixture.FunSpec with DbFixture { override def populateDb(db: Db) { // setup the fixture db.append("ScalaTest is ") } describe("Testing") { it("should be easy") { db => db.append("easy!") assert(db.toString === "ScalaTest is easy!") } it("should be fun") { db => db.append("fun!") assert(db.toString === "ScalaTest is fun!") } } // This test doesn't need a Db describe("Test code") { it("should be clear") { () => val buf = new StringBuffer buf.append("ScalaTest code is ") buf.append("clear!") assert(buf.toString === "ScalaTest code is clear!") } } }
Often when you create fixtures in a trait like DbFixture
, you'll still need to enable individual test classes
to "setup" a newly created fixture before it gets passed into the tests. A good way to accomplish this is to pass the newly
created fixture into a setup method, like populateDb
in the previous example, before passing it to the test
function. Classes that need to perform such setup can override the method, as does ExampleSpec
.
If a test doesn't need the fixture, you can indicate that by providing a no-arg instead of a one-arg function, as is done in the
third test in the previous example, “Test code should be clear
”. In other words, instead of starting your function literal
with something like “db =>
”, you'd start it with “() =>
”. For such tests, runTest
will not invoke withFixture(OneArgTest)
. It will instead directly invoke withFixture(NoArgTest)
.
Both examples shown above demonstrate the technique of giving each test its own "fixture sandbox" to play in. When your fixtures
involve external side-effects, like creating files or databases, it is a good idea to give each file or database a unique name as is
done in these examples. This keeps tests completely isolated, allowing you to run them in parallel if desired. You could mix
ParallelTestExecution
into either of these ExampleSpec
classes, and the tests would run in parallel just fine.
Implementation trait for class fixture.FunSpec
, which is
a sister class to org.scalatest.FunSpec
that can pass a
fixture object into its tests.
Implementation trait for class fixture.FunSpec
, which is
a sister class to org.scalatest.FunSpec
that can pass a
fixture object into its tests.
fixture.FunSpec
is a class,
not a trait, to minimize compile time given there is a slight compiler
overhead to mixing in traits compared to extending classes. If you need
to mix the behavior of fixture.FunSpec
into some other
class, you can use this trait instead, because class
fixture.FunSpec
does nothing more than extend this trait and add a nice toString
implementation.
See the documentation of the class for a detailed
overview of fixture.FunSpec
.
A sister class to org.scalatest.FunSuite
that can pass a fixture object into its tests.
A sister class to org.scalatest.FunSuite
that can pass a fixture object into its tests.
Recommended Usage:
Use class fixture.FunSuite in situations for which FunSuite
would be a good choice, when all or most tests need the same fixture objects
that must be cleaned up afterwards. Note: fixture.FunSuite is intended for use in special situations, with class FunSuite used for general needs. For
more insight into where fixture.FunSuite fits in the big picture, see the withFixture(OneArgTest) subsection of the Shared fixtures section in the documentation for class FunSuite .
|
Class fixture.FunSuite
behaves similarly to class org.scalatest.FunSuite
, except that tests may have a
fixture parameter. The type of the
fixture parameter is defined by the abstract FixtureParam
type, which is a member of this class.
This class also contains an abstract withFixture
method. This withFixture
method
takes a OneArgTest
, which is a nested trait defined as a member of this class.
OneArgTest
has an apply
method that takes a FixtureParam
.
This apply
method is responsible for running a test.
This class's runTest
method delegates the actual running of each test to withFixture(OneArgTest)
, passing
in the test code to run via the OneArgTest
argument. The withFixture(OneArgTest)
method (abstract in this class) is responsible
for creating the fixture argument and passing it to the test function.
Subclasses of this class must, therefore, do three things differently from a plain old org.scalatest.FunSuite
:
FixtureParam
withFixture(OneArgTest)
methodIf the fixture you want to pass into your tests consists of multiple objects, you will need to combine them into one object to use this class. One good approach to passing multiple fixture objects is to encapsulate them in a case class. Here's an example:
case class FixtureParam(file: File, writer: FileWriter)
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 the OneArgTest
to a NoArgTest
. You can do that by passing
the fixture object to the toNoArgTest
method of OneArgTest
. In other words, instead of
writing “test(theFixture)
”, you'd delegate responsibility for
invoking the test function to the withFixture(NoArgTest)
method of the same instance by writing:
withFixture(test.toNoArgTest(theFixture))
Here's a complete example:
package org.scalatest.examples.funsuite.oneargtest import org.scalatest.fixture import java.io._ class ExampleSuite extends fixture.FunSuite { case class FixtureParam(file: File, writer: FileWriter) def withFixture(test: OneArgTest) = { // create the fixture val file = File.createTempFile("hello", "world") val writer = new FileWriter(file) val theFixture = FixtureParam(file, writer) try { writer.write("ScalaTest is ") // set up the fixture withFixture(test.toNoArgTest(theFixture)) // "loan" the fixture to the test } finally writer.close() // clean up the fixture } test("testing should be easy") { f => f.writer.write("easy!") f.writer.flush() assert(f.file.length === 18) } test("testing should be fun") { f => f.writer.write("fun!") f.writer.flush() assert(f.file.length === 17) } }
If a test fails, the OneArgTest
function will result in a Failed wrapping the exception describing the failure.
To ensure clean up happens even if a test fails, you should invoke the test function from inside a try
block and do the cleanup in a
finally
clause, as shown in the previous example.
If multiple test classes need the same fixture, you can define the FixtureParam
and withFixture(OneArgTest)
implementations
in a trait, then mix that trait into the test classes that need it. For example, if your application requires a database and your integration tests
use that database, you will likely have many test classes that need a database fixture. You can create a "database fixture" trait that creates a
database with a unique name, passes the connector into the test, then removes the database once the test completes. This is shown in the following example:
package org.scalatest.examples.fixture.funsuite.sharing import java.util.concurrent.ConcurrentHashMap import org.scalatest.fixture import DbServer._ import java.util.UUID.randomUUID object DbServer { // Simulating a database server type Db = StringBuffer private val databases = new ConcurrentHashMap[String, Db] def createDb(name: String): Db = { val db = new StringBuffer databases.put(name, db) db } def removeDb(name: String) { databases.remove(name) } } trait DbFixture { this: fixture.Suite => type FixtureParam = Db // Allow clients to populate the database after // it is created def populateDb(db: Db) {} def withFixture(test: OneArgTest) = { val dbName = randomUUID.toString val db = createDb(dbName) // create the fixture try { populateDb(db) // setup the fixture withFixture(test.toNoArgTest(db)) // "loan" the fixture to the test } finally removeDb(dbName) // clean up the fixture } } class ExampleSuite extends fixture.FunSuite with DbFixture { override def populateDb(db: Db) { // setup the fixture db.append("ScalaTest is ") } test("testing should be easy") { db => db.append("easy!") assert(db.toString === "ScalaTest is easy!") } test("testing should be fun") { db => db.append("fun!") assert(db.toString === "ScalaTest is fun!") } // This test doesn't need a Db test("test code should be clear") { () => val buf = new StringBuffer buf.append("ScalaTest code is ") buf.append("clear!") assert(buf.toString === "ScalaTest code is clear!") } }
Often when you create fixtures in a trait like DbFixture
, you'll still need to enable individual test classes
to "setup" a newly created fixture before it gets passed into the tests. A good way to accomplish this is to pass the newly
created fixture into a setup method, like populateDb
in the previous example, before passing it to the test
function. Classes that need to perform such setup can override the method, as does ExampleSuite
.
If a test doesn't need the fixture, you can indicate that by providing a no-arg instead of a one-arg function, as is done in the
third test in the previous example, “test code should be clear
”. In other words, instead of starting your function literal
with something like “db =>
”, you'd start it with “() =>
”. For such tests, runTest
will not invoke withFixture(OneArgTest)
. It will instead directly invoke withFixture(NoArgTest)
.
Both examples shown above demonstrate the technique of giving each test its own "fixture sandbox" to play in. When your fixtures
involve external side-effects, like creating files or databases, it is a good idea to give each file or database a unique name as is
done in these examples. This keeps tests completely isolated, allowing you to run them in parallel if desired. You could mix
ParallelTestExecution
into either of these ExampleSuite
classes, and the tests would run in parallel just fine.
Implementation trait for class fixture.FunSuite
, which is
a sister class to org.scalatest.FunSuite
that can pass a
fixture object into its tests.
Implementation trait for class fixture.FunSuite
, which is
a sister class to org.scalatest.FunSuite
that can pass a
fixture object into its tests.
fixture.FunSuite
is a class,
not a trait, to minimize compile time given there is a slight compiler
overhead to mixing in traits compared to extending classes. If you need
to mix the behavior of fixture.FunSuite
into some other
class, you can use this trait instead, because class
fixture.FunSuite
does nothing more than extend this trait and add a nice toString
implementation.
See the documentation of the class for a detailed
overview of fixture.FunSuite
.
A function that takes no parameters (i.e., a Function0
or "no-arg" function) and results in Unit
, which when
invoked executes the body of the constructor of the class into which this trait is mixed.
A function that takes no parameters (i.e., a Function0
or "no-arg" function) and results in Unit
, which when
invoked executes the body of the constructor of the class into which this trait is mixed.
This trait extends DelayedInit
and defines a delayedInit
method that
saves the body of the constructor (passed to delayedInit
) for later execution when apply
is invoked.
This trait is somewhat magical and therefore may be challenging for your collegues to understand, so please use it as a last resort only when the
simpler options described in the "shared fixtures" section of your chosen style trait won't do
the job. NoArg
is
intended to address a specific use case that will likely be rare, and is unlikely to be useful outside of its intended use case, but
it is quite handy for its intended use case (described in the next paragraph).
One potential gotcha, for example, is that a subclass's constructor body could in theory be executed multiple times by simply invoking apply
multiple
times. In the intended use case for this trait, however, the body will be executed only once.
The intended use case for this method is (relatively rare) situations in which you want to extend a different instance of the same class for each test, with the body of the test inheriting the members of that class, and with code executed before and/or after the body of the test.
For example, Akka's TestKit
class takes an ActorSystem
,
which must have a unique name. To run a suite of tests in parallel, each test must get its own ActorSystem
, to
ensure the tests run in isolation. At the end of each test, the ActorSystem
must be shutdown. With NoArg
,
you can achieve this by first defining a class that extends TestKit
and mixes in NoArg
.
Here's an example taken with permission from the book Akka Concurrency, by Derek Wyatt:
import akka.actor.ActorSystem import akka.testkit.{TestKit, ImplicitSender} import java.util.concurrent.atomic.AtomicInteger import org.scalatest.fixture.NoArg object ActorSys { val uniqueId = new AtomicInteger(0) } class ActorSys(name: String) extends TestKit(ActorSystem(name)) with ImplicitSender with NoArg { def this() = this( "TestSystem%05d".format( ActorSys.uniqueId.getAndIncrement())) def shutdown(): Unit = system.shutdown() override def apply() { try super.apply() finally shutdown() } }
Given this implementation of ActorSys
, which will invoke shutdown
after the constructor code
is executed, you can run each test in a suite in a subclass of TestKit
, giving each test's TestKit
an ActorSystem
with a unique name, allowing you to safely run those tests in parallel. Here's an example
from Akka Concurrency:
class MyActorSpec extends fixture.WordSpec with Matchers with UnitFixture with ParallelTestExecution { def makeActor(): ActorRef = system.actorOf(Props[MyActor], "MyActor") "My Actor" should { "throw when made with the wrong name" in new ActorSys { an [Exception] should be thrownBy { // use a generated name val a = system.actorOf(Props[MyActor]) } } "construct without exception" in new ActorSys { val a = makeActor() // The throw will cause the test to fail } "respond with a Pong to a Ping" in new ActorSys { val a = makeActor() a ! Ping expectMsg(Pong) } } }
UnitFixture
is used in this example, because in this case, the fixture.WordSpec
feature enabling tests to be defined as
functions from fixture objects of type FixtureParam
to Unit
is not being used. Rather, only the secondary feature that enables
tests to be defined as functions from no parameters to Unit
is being used. This secondary feature is described in the second-to-last
paragraph on the main Scaladoc documentation of fixture.WordSpec
, which says:
If a test doesn't need the fixture, you can indicate that by providing a no-arg instead of a one-arg function, ... In other words, instead of starting your function literal with something like “db =>
”, you'd start it with “() =>
”. For such tests,runTest
will not invokewithFixture(OneArgTest)
. It will instead directly invokewithFixture(NoArgTest)
.
Since FixtureParam
is unused in this use case, it could
be anything. Making it Unit
will hopefully help readers more easily recognize that it is not being used.
Note: As of Scala 2.11, DelayedInit
(which is used by NoArg
) has been deprecated, to indicate it is buggy and should be avoided
if possible. Those in charge of the Scala compiler and standard library have promised that DelayedInit
will not be removed from Scala
unless an alternate way to achieve the same goal is provided. Thus it should be safe to use NoArg
, but if you'd rather
not you can achieve the same effect with a bit more boilerplate by extending (() => Unit
) instead of NoArg
and placing
your code in an explicit body
method. Here's an example:
import akka.actor.ActorSystem import akka.testkit.{TestKit, ImplicitSender} import java.util.concurrent.atomic.AtomicInteger import org.scalatest.fixture.NoArg object ActorSys { val uniqueId = new AtomicInteger(0) } class ActorSys(name: String) extends TestKit(ActorSystem(name)) with ImplicitSender with (() => Unit) { def this() = this( "TestSystem%05d".format( ActorSys.uniqueId.getAndIncrement())) def shutdown(): Unit = system.shutdown() def body(): Unit override def apply() = { try body() finally shutdown() } }
Using this version of ActorSys
will require an explicit
body
method in the tests:
class MyActorSpec extends fixture.WordSpec with Matchers with UnitFixture with ParallelTestExecution { def makeActor(): ActorRef = system.actorOf(Props[MyActor], "MyActor") "My Actor" should { "throw when made with the wrong name" in new ActorSys { def body() = an [Exception] should be thrownBy { // use a generated name val a = system.actorOf(Props[MyActor]) } } "construct without exception" in new ActorSys { def body() = { val a = makeActor() // The throw will cause the test to fail } } "respond with a Pong to a Ping" in new ActorSys { def body() = { val a = makeActor() a ! Ping expectMsg(Pong) } } } }
A sister class to org.scalatest.PropSpec
that can pass a fixture object into its tests.
A sister class to org.scalatest.PropSpec
that can pass a fixture object into its tests.
Recommended Usage:
Use class fixture.PropSpec in situations for which PropSpec
would be a good choice, when all or most tests need the same fixture objects
that must be cleaned up afterwards. Note: fixture.PropSpec is intended for use in special
situations, with class PropSpec used for general needs. For
more insight into where fixture.PropSpec fits in the big picture, see
the withFixture(OneArgTest) subsection of
the Shared fixtures section in the documentation for class PropSpec .
|
Class fixture.PropSpec
behaves similarly to class org.scalatest.PropSpec
, except that tests may have a
fixture parameter. The type of the
fixture parameter is defined by the abstract FixtureParam
type, which is a member of this class.
This class also has an abstract withFixture
method. This withFixture
method
takes a OneArgTest
, which is a nested trait defined as a member of this class.
OneArgTest
has an apply
method that takes a FixtureParam
.
This apply
method is responsible for running a test.
This class's runTest
method delegates the actual running of each test to withFixture
, passing
in the test code to run via the OneArgTest
argument. The withFixture
method (abstract in this class) is responsible
for creating the fixture argument and passing it to the test function.
Subclasses of this class must, therefore, do three things differently from a plain old org.scalatest.PropSpec
:
FixtureParam
withFixture(OneArgTest)
methodHere's an example:
package org.scalatest.examples.fixture.propspec import org.scalatest._ import prop.PropertyChecks import java.io._ class ExampleSpec extends fixture.PropSpec with PropertyChecks with ShouldMatchers { // 1. define type FixtureParam type FixtureParam = FileReader // 2. define the withFixture method def withFixture(test: OneArgTest) = { val FileName = "TempFile.txt" // Set up the temp file needed by the test val writer = new FileWriter(FileName) try { writer.write("Hello, test!") } finally { writer.close() } // Create the reader needed by the test val reader = new FileReader(FileName) try { // Run the test using the temp file test(reader) } finally { // Close and delete the temp file reader.close() val file = new File(FileName) file.delete() } } // 3. write property-based tests that take a fixture parameter // (Hopefully less contrived than the examples shown here.) property("can read from a temp file") { reader => var builder = new StringBuilder var c = reader.read() while (c != -1) { builder.append(c.toChar) c = reader.read() } val fileContents = builder.toString forAll { (c: Char) => whenever (c != 'H') { fileContents should not startWith c.toString } } } property("can read the first char of the temp file") { reader => val firstChar = reader.read() forAll { (c: Char) => whenever (c != 'H') { c should not equal firstChar } } } // (You can also write tests that don't take a fixture parameter.) property("can write tests that don't take the fixture") { () => forAll { (i: Int) => i + i should equal (2 * i) } } }
Note: to run the examples on this page, you'll need to include ScalaCheck on the classpath in addition to ScalaTest.
In the previous example, withFixture
creates and initializes a temp file, then invokes the test function,
passing in a FileReader
connected to that file. In addition to setting up the fixture before a test,
the withFixture
method also cleans it up afterwards. If you need to do some clean up
that must happen even if a test fails, you should invoke the test function from inside a try
block and do
the cleanup in a finally
clause, as shown in the previous example.
If a test fails, the OneArgTest
function will result in a Failed wrapping the
exception describing the failure.
The reason you must perform cleanup in a finally
clause is that in case an exception propagates back through
withFixture
, the finally
clause will ensure the fixture cleanup happens as that exception
propagates back up the call stack to runTest
.
If a test doesn't need the fixture, you can indicate that by providing a no-arg instead of a one-arg function.
In other words, instead of starting your function literal
with something like “reader =>
”, you'd start it with “() =>
”, as is done
in the third test in the above example. For such tests, runTest
will not invoke withFixture(OneArgTest)
. It will instead directly invoke withFixture(NoArgTest)
.
If the fixture you want to pass into your tests consists of multiple objects, you will need to combine them into one object to use this class. One good approach to passing multiple fixture objects is to encapsulate them in a case class. Here's an example:
case class FixtureParam(builder: StringBuilder, buffer: ListBuffer[String])
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 the OneArgTest
to a NoArgTest
. You can do that by passing
the fixture object to the toNoArgTest
method of OneArgTest
. In other words, instead of
writing “test(theFixture)
”, you'd delegate responsibility for
invoking the test function to the withFixture(NoArgTest)
method of the same instance by writing:
withFixture(test.toNoArgTest(theFixture))
Here's a complete example:
package org.scalatest.examples.fixture.propspec.multi import org.scalatest._ import prop.PropertyChecks import scala.collection.mutable.ListBuffer class ExampleSpec extends fixture.PropSpec with PropertyChecks with ShouldMatchers { case class FixtureParam(builder: StringBuilder, buffer: ListBuffer[String]) def withFixture(test: OneArgTest) = { // Create needed mutable objects val stringBuilder = new StringBuilder("ScalaTest is ") val listBuffer = new ListBuffer[String] val theFixture = FixtureParam(stringBuilder, listBuffer) // Invoke the test function, passing in the mutable objects withFixture(test.toNoArgTest(theFixture)) } property("testing should be easy") { f => f.builder.append("easy!") assert(f.builder.toString === "ScalaTest is easy!") assert(f.buffer.isEmpty) val firstChar = f.builder(0) forAll { (c: Char) => whenever (c != 'S') { c should not equal firstChar } } f.buffer += "sweet" } property("testing should be fun") { f => f.builder.append("fun!") assert(f.builder.toString === "ScalaTest is fun!") assert(f.buffer.isEmpty) val firstChar = f.builder(0) forAll { (c: Char) => whenever (c != 'S') { c should not equal firstChar } } } }
Implementation trait for class fixture.PropSpec
, which is
a sister class to org.scalatest.PropSpec
that can pass a
fixture object into its tests.
Implementation trait for class fixture.PropSpec
, which is
a sister class to org.scalatest.PropSpec
that can pass a
fixture object into its tests.
fixture.PropSpec
is a class,
not a trait, to minimize compile time given there is a slight compiler
overhead to mixing in traits compared to extending classes. If you need
to mix the behavior of fixture.PropSpec
into some other
class, you can use this trait instead, because class
fixture.PropSpec
does nothing more than extend this trait and add a nice toString
implementation.
See the documentation of the class for a detailed
overview of fixture.PropSpec
.
A sister class to org.scalatest.Spec
that can pass a fixture object into its tests.
A sister class to org.scalatest.Spec
that can pass a fixture object into its tests.
Recommended Usage:
Use class fixture.Spec in situations for which Spec
would be a good choice, when all or most tests need the same fixture objects
that must be cleaned up afterwards. Note: fixture.Spec is intended for use in special situations, with class Spec used for general needs. For
more insight into where fixture.Spec fits in the big picture, see the withFixture(OneArgTest) subsection of the Shared fixtures section in the documentation for class Spec .
|
Class fixture.Spec
behaves similarly to class org.scalatest.Spec
, except that tests may have a
fixture parameter. The type of the
fixture parameter is defined by the abstract FixtureParam
type, which is a member of this class.
This class also has an abstract withFixture
method. This withFixture
method
takes a OneArgTest
, which is a nested trait defined as a member of this class.
OneArgTest
has an apply
method that takes a FixtureParam
.
This apply
method is responsible for running a test.
This class's runTest
method delegates the actual running of each test to withFixture(OneArgTest)
, passing
in the test code to run via the OneArgTest
argument. The withFixture(OneArgTest)
method (abstract in this class) is responsible
for creating the fixture argument and passing it to the test function.
Subclasses of this class must, therefore, do three things differently from a plain old org.scalatest.Spec
:
FixtureParam
withFixture(OneArgTest)
methodIf the fixture you want to pass into your tests consists of multiple objects, you will need to combine them into one object to use this class. One good approach to passing multiple fixture objects is to encapsulate them in a case class. Here's an example:
case class FixtureParam(file: File, writer: FileWriter)
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 the OneArgTest
to a NoArgTest
. You can do that by passing
the fixture object to the toNoArgTest
method of OneArgTest
. In other words, instead of
writing “test(theFixture)
”, you'd delegate responsibility for
invoking the test function to the withFixture(NoArgTest)
method of the same instance by writing:
withFixture(test.toNoArgTest(theFixture))
Here's a complete example:
package org.scalatest.examples.spec.oneargtest import org.scalatest.fixture import java.io._ class ExampleSpec extends fixture.Spec { case class FixtureParam(file: File, writer: FileWriter) def withFixture(test: OneArgTest) = { // create the fixture val file = File.createTempFile("hello", "world") val writer = new FileWriter(file) val theFixture = FixtureParam(file, writer) try { writer.write("ScalaTest is ") // set up the fixture withFixture(test.toNoArgTest(theFixture)) // "loan" the fixture to the test } finally writer.close() // clean up the fixture } object `Testing ` { def `should be easy` { f: FixtureParam => f.writer.write("easy!") f.writer.flush() assert(f.file.length === 18) } def `should be fun` { f: FixtureParam => f.writer.write("fun!") f.writer.flush() assert(f.file.length === 17) } } }
If a test fails, the OneArgTest
function will result in a Failed wrapping the exception describing the failure.
To ensure clean up happens even if a test fails, you should invoke the test function from inside a try
block and do the cleanup in a
finally
clause, as shown in the previous example.
If multiple test classes need the same fixture, you can define the FixtureParam
and withFixture(OneArgTest)
implementations
in a trait, then mix that trait into the test classes that need it. For example, if your application requires a database and your integration tests
use that database, you will likely have many test classes that need a database fixture. You can create a "database fixture" trait that creates a
database with a unique name, passes the connector into the test, then removes the database once the test completes. This is shown in the following example:
package org.scalatest.examples.fixture.spec.sharing import java.util.concurrent.ConcurrentHashMap import org.scalatest.fixture import DbServer._ import java.util.UUID.randomUUID object DbServer { // Simulating a database server type Db = StringBuffer private val databases = new ConcurrentHashMap[String, Db] def createDb(name: String): Db = { val db = new StringBuffer databases.put(name, db) db } def removeDb(name: String) { databases.remove(name) } } trait DbFixture { this: fixture.Suite => type FixtureParam = Db // Allow clients to populate the database after // it is created def populateDb(db: Db) {} def withFixture(test: OneArgTest) = { val dbName = randomUUID.toString val db = createDb(dbName) // create the fixture try { populateDb(db) // setup the fixture withFixture(test.toNoArgTest(db)) // "loan" the fixture to the test } finally removeDb(dbName) // clean up the fixture } } class ExampleSpec extends fixture.Spec with DbFixture { override def populateDb(db: Db) { // setup the fixture db.append("ScalaTest is ") } object `Testing ` { def `should be easy` (db: Db) { db.append("easy!") assert(db.toString === "ScalaTest is easy!") } def `should be fun` (db: Db) { db.append("fun!") assert(db.toString === "ScalaTest is fun!") } } // This test doesn't need a Db object `Test code` { def `should be clear` { val buf = new StringBuffer buf.append("ScalaTest code is ") buf.append("clear!") assert(buf.toString === "ScalaTest code is clear!") } } }
Often when you create fixtures in a trait like DbFixture
, you'll still need to enable individual test classes
to "setup" a newly created fixture before it gets passed into the tests. A good way to accomplish this is to pass the newly
created fixture into a setup method, like populateDb
in the previous example, before passing it to the test
function. Classes that need to perform such setup can override the method, as does ExampleSpec
.
If a test doesn't need the fixture, you can indicate that by leaving off the fixture parameter, as is done in the
third test in the previous example, “Test code should be clear
”. For such methods, runTest
will not invoke withFixture(OneArgTest)
. It will instead directly invoke withFixture(NoArgTest)
.
Both examples shown above demonstrate the technique of giving each test its own "fixture sandbox" to play in. When your fixtures
involve external side-effects, like creating files or databases, it is a good idea to give each file or database a unique name as is
done in these examples. This keeps tests completely isolated, allowing you to run them in parallel if desired. You could mix
ParallelTestExecution
into either of these ExampleSpec
classes, and the tests would run in parallel just fine.
Implementation trait for class fixture.Spec
, which is
a sister class to org.scalatest.Spec
that can pass a
fixture object into its tests.
Implementation trait for class fixture.Spec
, which is
a sister class to org.scalatest.Spec
that can pass a
fixture object into its tests.
fixture.Spec
is a class,
not a trait, to minimize compile time given there is a slight compiler
overhead to mixing in traits compared to extending classes. If you need
to mix the behavior of fixture.Spec
into some other
class, you can use this trait instead, because class
fixture.Spec
does nothing more than extend this trait and add a nice toString
implementation.
See the documentation of the class for a detailed
overview of fixture.Spec
.
Base trait for a family of style traits that can pass a fixture object into tests.
Trait that when mixed into a fixture.Suite
passes the
TestData
passed to withFixture
as a fixture into each test.
Trait that when mixed into a fixture.Suite
passes the
TestData
passed to withFixture
as a fixture into each test.
For example, here's how you could access the test's name in each test using TestDataFixture
:
package org.scalatest.examples.fixture.testdatafixture import org.scalatest._ class ExampleSpec extends fixture.FlatSpec with fixture.TestDataFixture { "Accessing the test data" should "be easy!" in { td => assert(td.name == "Accessing the test data should be easy!") } it should "be fun!" in { td => assert(td.name == "Accessing the test data should be fun!") } }
Trait that when mixed into a fixture.Suite
passes
the unit value as a fixture into each test.
Trait that when mixed into a fixture.Suite
passes
the unit value as a fixture into each test.
Since a unit value is unlikely to be of much use to a test, this trait is useful
when the unit value fixture is actually never passed into any tests. Instead
each test in the fixture.Suite
is defined as a no-arg function; no tests are defined as one-arg functions.
This should be quite rare, but occasionally can be useful.
For an example, see the main documentation for trait NoArg
.
A sister class to org.scalatest.WordSpec
that can pass a fixture object into its tests.
A sister class to org.scalatest.WordSpec
that can pass a fixture object into its tests.
Recommended Usage:
Use class fixture.WordSpec in situations for which WordSpec
would be a good choice, when all or most tests need the same fixture objects
that must be cleaned up afterwards. Note: fixture.WordSpec is intended for use in special situations, with class WordSpec used for general needs. For
more insight into where fixture.WordSpec fits in the big picture, see the withFixture(OneArgTest) subsection of the Shared fixtures section in the documentation for class WordSpec .
|
Class fixture.WordSpec
behaves similarly to class org.scalatest.WordSpec
, except that tests may have a
fixture parameter. The type of the
fixture parameter is defined by the abstract FixtureParam
type, which is a member of this class.
This class also has an abstract withFixture
method. This withFixture
method
takes a OneArgTest
, which is a nested trait defined as a member of this class.
OneArgTest
has an apply
method that takes a FixtureParam
.
This apply
method is responsible for running a test.
This class's runTest
method delegates the actual running of each test to withFixture(OneArgTest)
, passing
in the test code to run via the OneArgTest
argument. The withFixture(OneArgTest)
method (abstract in this class) is responsible
for creating the fixture argument and passing it to the test function.
Subclasses of this class must, therefore, do three things differently from a plain old org.scalatest.WordSpec
:
FixtureParam
withFixture(OneArgTest)
methodIf the fixture you want to pass into your tests consists of multiple objects, you will need to combine them into one object to use this class. One good approach to passing multiple fixture objects is to encapsulate them in a case class. Here's an example:
case class FixtureParam(file: File, writer: FileWriter)
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 the OneArgTest
to a NoArgTest
. You can do that by passing
the fixture object to the toNoArgTest
method of OneArgTest
. In other words, instead of
writing “test(theFixture)
”, you'd delegate responsibility for
invoking the test function to the withFixture(NoArgTest)
method of the same instance by writing:
withFixture(test.toNoArgTest(theFixture))
Here's a complete example:
package org.scalatest.examples.wordspec.oneargtest import org.scalatest.fixture import java.io._ class ExampleSpec extends fixture.WordSpec { case class FixtureParam(file: File, writer: FileWriter) def withFixture(test: OneArgTest) = { // create the fixture val file = File.createTempFile("hello", "world") val writer = new FileWriter(file) val theFixture = FixtureParam(file, writer) try { writer.write("ScalaTest is ") // set up the fixture withFixture(test.toNoArgTest(theFixture)) // "loan" the fixture to the test } finally writer.close() // clean up the fixture } "Testing" should { "be easy" in { f => f.writer.write("easy!") f.writer.flush() assert(f.file.length === 18) } "be fun" in { f => f.writer.write("fun!") f.writer.flush() assert(f.file.length === 17) } } }
If a test fails, the OneArgTest
function will result in a Failed wrapping the exception describing the failure.
To ensure clean up happens even if a test fails, you should invoke the test function from inside a try
block and do the cleanup in a
finally
clause, as shown in the previous example.
If multiple test classes need the same fixture, you can define the FixtureParam
and withFixture(OneArgTest)
implementations
in a trait, then mix that trait into the test classes that need it. For example, if your application requires a database and your integration tests
use that database, you will likely have many test classes that need a database fixture. You can create a "database fixture" trait that creates a
database with a unique name, passes the connector into the test, then removes the database once the test completes. This is shown in the following example:
package org.scalatest.examples.fixture.wordspec.sharing import java.util.concurrent.ConcurrentHashMap import org.scalatest.fixture import DbServer._ import java.util.UUID.randomUUID object DbServer { // Simulating a database server type Db = StringBuffer private val databases = new ConcurrentHashMap[String, Db] def createDb(name: String): Db = { val db = new StringBuffer databases.put(name, db) db } def removeDb(name: String) { databases.remove(name) } } trait DbFixture { this: fixture.Suite => type FixtureParam = Db // Allow clients to populate the database after // it is created def populateDb(db: Db) {} def withFixture(test: OneArgTest) = { val dbName = randomUUID.toString val db = createDb(dbName) // create the fixture try { populateDb(db) // setup the fixture withFixture(test.toNoArgTest(db)) // "loan" the fixture to the test } finally removeDb(dbName) // clean up the fixture } } class ExampleSpec extends fixture.WordSpec with DbFixture { override def populateDb(db: Db) { // setup the fixture db.append("ScalaTest is ") } "Testing" should { "should be easy" in { db => db.append("easy!") assert(db.toString === "ScalaTest is easy!") } "should be fun" in { db => db.append("fun!") assert(db.toString === "ScalaTest is fun!") } } // This test doesn't need a Db "Test code" should { "should be clear" in { () => val buf = new StringBuffer buf.append("ScalaTest code is ") buf.append("clear!") assert(buf.toString === "ScalaTest code is clear!") } } }
Often when you create fixtures in a trait like DbFixture
, you'll still need to enable individual test classes
to "setup" a newly created fixture before it gets passed into the tests. A good way to accomplish this is to pass the newly
created fixture into a setup method, like populateDb
in the previous example, before passing it to the test
function. Classes that need to perform such setup can override the method, as does ExampleSpec
.
If a test doesn't need the fixture, you can indicate that by providing a no-arg instead of a one-arg function, as is done in the
third test in the previous example, “Test code should be clear
”. In other words, instead of starting your function literal
with something like “db =>
”, you'd start it with “() =>
”. For such tests, runTest
will not invoke withFixture(OneArgTest)
. It will instead directly invoke withFixture(NoArgTest)
.
Both examples shown above demonstrate the technique of giving each test its own "fixture sandbox" to play in. When your fixtures
involve external side-effects, like creating files or databases, it is a good idea to give each file or database a unique name as is
done in these examples. This keeps tests completely isolated, allowing you to run them in parallel if desired. You could mix
ParallelTestExecution
into either of these ExampleSpec
classes, and the tests would run in parallel just fine.
Implementation trait for class fixture.WordSpec
, which is
a sister class to org.scalatest.WordSpec
that can pass a
fixture object into its tests.
Implementation trait for class fixture.WordSpec
, which is
a sister class to org.scalatest.WordSpec
that can pass a
fixture object into its tests.
fixture.WordSpec
is a class,
not a trait, to minimize compile time given there is a slight compiler
overhead to mixing in traits compared to extending classes. If you need
to mix the behavior of fixture.WordSpec
into some other
class, you can use this trait instead, because class
fixture.WordSpec
does nothing more than extend this trait and add a nice toString
implementation.
See the documentation of the class for a detailed
overview of fixture.WordSpec
.
Implementation trait for class
fixture.FeatureSpec
, which is a sister class toorg.scalatest.FeatureSpec
that can pass a fixture object into its tests.fixture.FeatureSpec
is a class, not a trait, to minimize compile time given there is a slight compiler overhead to mixing in traits compared to extending classes. If you need to mix the behavior offixture.FeatureSpec
into some other class, you can use this trait instead, because classfixture.FeatureSpec
does nothing more than extend this trait and add a nicetoString
implementation.See the documentation of the class for a detailed overview of
fixture.FeatureSpec
.