Package

org

scalatest

Permalink

package scalatest

ScalaTest's main traits, classes, and other members, including members supporting ScalaTest's DSL for the Scala interpreter.

Linear Supertypes
AnyRef, Any
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. scalatest
  2. AnyRef
  3. Any
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. All

Type Members

  1. trait Alerter extends AnyRef

    Permalink

    Trait providing an apply method to which alert messages about a running suite of tests can be reported.

    Trait providing an apply method to which alert messages about a running suite of tests can be reported.

    An Alerter is essentially used to wrap a Reporter and provide easy ways to send alert messages to that Reporter via an AlertProvided event. Alerter contains an apply method that takes a string and an optional payload object of type Any. The Alerter will forward the passed alert message string to the Reporter as the message parameter, and the optional payload object as the payload parameter, of an AlertProvided event.

    For insight into the differences between Alerter, Notifier, and Informer, see the main documentation for trait Alerting.

  2. trait Alerting extends AnyRef

    Permalink

    Trait that contains the alert method, which can be used to send an alert to the reporter.

    Trait that contains the alert method, which can be used to send an alert to the reporter.

    One difference between alert and the info method of Informer is that info messages provided during a test are recorded and sent as part of test completion event, whereas alert messages are sent right away as AlertProvided messages. For long-running tests, alert allows you to send "alert notifications" to the reporter right away, so users can be made aware of potential problems being experienced by long-running tests. By contrast, info messages will only be seen by the user after the test has completed, and are more geared towards specification (such as Given/When/Then messages) than notification.

    The difference between alert and the update method of Updating is that alert is intended to be used for warnings or notifications of potential problems, whereas update is just for status updates. In string reporters for which ANSI color is enabled, update notifications are shown in green and alert notifications in yellow.

  3. trait AppendedClues extends AnyRef

    Permalink

    Trait providing an implicit conversion that allows clues to be placed after a block of code.

    Trait providing an implicit conversion that allows clues to be placed after a block of code.

    You can use the withClue construct provided by Assertions, which is extended by every style trait in ScalaTest, to add extra information to reports of failed or canceled tests. The withClue from Assertions places the "clue string" at the front, both in the code and in the resulting message:

    withClue("This is a prepended clue;") {
      1 + 1 should equal (3)
    }
    

    The above expression will yield the failure message:

    This is a prepended clue; 2 did not equal 3

    If you mix in this trait, or import its members via its companion object, you can alternatively place the clue string at the end, like this:

    { 1 + 1 should equal (3) } withClue "now the clue comes after"
    

    The above expression will yield the failure message:

    2 did not equal 3 now the clue comes after

    If no space is already present, either at the beginning of the clue string or at the end of the current message, a space will be placed between the two, unless the clue string starts with one of the punctuation characters: comma (,), period (.), or semicolon (;). For example, the failure message in the above example includes an extra space inserted between 3 and now.

    By contrast this code, which has a clue string starting with comma:

    { 1 + 1 should equal (3) } withClue ", now the clue comes after"
    

    Will yield a failure message with no extra inserted space:

    2 did not equal 3, now the clue comes after

    The withClue method will only append the clue string to the detail message of exception types that mix in the ModifiableMessage trait. See the documentation for ModifiableMessage for more information.

    Note: the reason this functionality is not provided by Assertions directly, like the prepended withClue construct, is because appended clues require an implicit conversion. ScalaTest only gives you one implicit conversion by default in any test class to minimize the potential for conflicts with other implicit conversions you may be using. All other implicit conversions, including the one provided by this trait, you must explicitly invite into your code through inheritance or an import.

  4. case class Args(reporter: Reporter, stopper: Stopper = Stopper.default, filter: Filter = Filter.default, configMap: ConfigMap = ConfigMap.empty, distributor: Option[Distributor] = None, tracker: Tracker = Tracker.default, chosenStyles: Set[String] = Set.empty, runTestInNewInstance: Boolean = false, distributedTestSorter: Option[DistributedTestSorter] = None, distributedSuiteSorter: Option[DistributedSuiteSorter] = None) extends Product with Serializable

    Permalink

    Arguments bundle passed to four of ScalaTest's lifecycle methods: run, runNestedSuites, runTests, and runTest.

    Arguments bundle passed to four of ScalaTest's lifecycle methods: run, runNestedSuites, runTests, and runTest.

    The signatures of these methods, defined in trait Suite, are:

    def run(testName: Option[String], args: Args)
    def runNestedSuites(args: Args)
    def runTests(testName: Option[String], args: Args)
    def runTest(testName: String, args: Args)
    

    The purpose of bundling these arguments into an Args object instead of passing them in individually is to make the signature of these four lifecycle methods easier to read, write, and remember, as well as to make the methods more pleasant to override in user code.

    reporter

    the Reporter to which results will be reported

    stopper

    the Stopper that will be consulted to determine whether to stop execution early.

    filter

    a Filter with which to filter tests based on their tags

    configMap

    a ConfigMap of key-value pairs that can be used by the executing Suite of tests.

    distributor

    an optional Distributor, into which to put nested Suites to be executed by another entity, such as concurrently by a pool of threads. If None, nested Suites will be executed sequentially.

    tracker

    a Tracker tracking Ordinals being fired by the current thread.

    chosenStyles

    a (possibly empty) Set of Strings specifying the run's chosen styles

    runTestInNewInstance

    a flag used to pass information between run methods in OneInstancePerTest and ParallelTestExecution.

    distributedTestSorter

    an optional DistributedTestSorter used by ParallelTestExecution to sort the events for the parallel-executed tests of one suite back into sequential order on the fly, with a timeout in case a test takes too long to complete

    distributedSuiteSorter

    an optional DistributedSuiteSorter used by ParallelTestExecution to ensure the events for the parallel-executed suites are sorted back into sequential order, with a timeout in case a suite takes to long to complete, even when tests are executed in parallel

    Exceptions thrown

    NullArgumentException if any passed parameter is null.

  5. type Assertion = scalatest.compatible.Assertion

    Permalink
  6. trait Assertions extends TripleEquals

    Permalink

    Trait that contains ScalaTest's basic assertion methods.

    Trait that contains ScalaTest's basic assertion methods.

    You can use the assertions provided by this trait in any ScalaTest Suite, because Suite mixes in this trait. This trait is designed to be used independently of anything else in ScalaTest, though, so you can mix it into anything. (You can alternatively import the methods defined in this trait. For details, see the documentation for the Assertions companion object.

    In any Scala program, you can write assertions by invoking assert and passing in a Boolean expression, such as:

    val left = 2
    val right = 1
    assert(left == right)
    

    If the passed expression is true, assert will return normally. If false, Scala's assert will complete abruptly with an AssertionError. This behavior is provided by the assert method defined in object Predef, whose members are implicitly imported into every Scala source file. This Assertions trait defines another assert method that hides the one in Predef. It behaves the same, except that if false is passed it throws TestFailedException instead of AssertionError. Why? Because unlike AssertionError, TestFailedException carries information about exactly which item in the stack trace represents the line of test code that failed, which can help users more quickly find an offending line of code in a failing test. In addition, ScalaTest's assert provides better error messages than Scala's assert.

    If you pass the previous Boolean expression, left == right to assert in a ScalaTest test, a failure will be reported that, because assert is implemented as a macro, includes reporting the left and right values. For example, given the same code as above but using ScalaTest assertions:

    import org.scalatest.Assertions._
    val left = 2
    val right = 1
    assert(left == right)
    

    The detail message in the thrown TestFailedException from this assert will be: "2 did not equal 1".

    ScalaTest's assert macro works by recognizing patterns in the AST of the expression passed to assert and, for a finite set of common expressions, giving an error message that an equivalent ScalaTest matcher expression would give. Here are some examples, where a is 1, b is 2, c is 3, d is 4, xs is List(a, b, c), and num is 1.0:

    assert(a == b || c >= d)
    // Error message: 1 did not equal 2, and 3 was not greater than or equal to 4
    
    assert(xs.exists(_ == 4))
    // Error message: List(1, 2, 3) did not contain 4
    
    assert("hello".startsWith("h") && "goodbye".endsWith("y"))
    // Error message: "hello" started with "h", but "goodbye" did not end with "y"
    
    assert(num.isInstanceOf[Int])
    // Error message: 1.0 was not instance of scala.Int
    
    assert(Some(2).isEmpty)
    // Error message: Some(2) was not empty
    

    For expressions that are not recognized, the macro currently prints out a string representation of the (desugared) AST and adds "was false". Here are some examples of error messages for unrecognized expressions:

    assert(None.isDefined)
    // Error message: scala.None.isDefined was false
    
    assert(xs.exists(i => i > 10))
    // Error message: xs.exists(((i: Int) => i.>(10))) was false
    

    You can augment the standard error message by providing a String as a second argument to assert, like this:

    val attempted = 2
    assert(attempted == 1, "Execution was attempted " + left + " times instead of 1 time")
    

    Using this form of assert, the failure report will be more specific to your problem domain, thereby helping you debug the problem. This Assertions trait also mixes in the TripleEquals, which gives you a === operator that allows you to customize Equality, perform equality checks with numeric Tolerance, and enforce type constraints at compile time with sibling traits TypeCheckedTripleEquals and ConversionCheckedTripleEquals.

    Expected results

    Although the assert macro provides a natural, readable extension to Scala's assert mechanism that provides good error messages, as the operands become lengthy, the code becomes less readable. In addition, the error messages generated for == and === comparisons don't distinguish between actual and expected values. The operands are just called left and right, because if one were named expected and the other actual, it would be difficult for people to remember which was which. To help with these limitations of assertions, Suite includes a method called assertResult that can be used as an alternative to assert. To use assertResult, you place the expected value in parentheses after assertResult, followed by curly braces containing code that should result in the expected value. For example:

    val a = 5
    val b = 2
    assertResult(2) {
      a - b
    }
    

    In this case, the expected value is 2, and the code being tested is a - b. This assertion will fail, and the detail message in the TestFailedException will read, "Expected 2, but got 3."

    Forcing failures

    If you just need the test to fail, you can write:

    fail()
    

    Or, if you want the test to fail with a message, write:

    fail("I've got a bad feeling about this")
    

    Achieving success

    In async style tests, you must end your test body with either Future[Assertion] or Assertion. ScalaTest's assertions (including matcher expressions) have result type Assertion, so ending with an assertion will satisfy the compiler. If a test body or function body passed to Future.map does not end with type Assertion, however, you can fix the type error by placing succeed at the end of the test or function body:

    succeed // Has type Assertion
    

    Expected exceptions

    Sometimes you need to test whether a method throws an expected exception under certain circumstances, such as when invalid arguments are passed to the method. You can do this in the JUnit 3 style, like this:

    val s = "hi"
    try {
      s.charAt(-1)
      fail()
    }
    catch {
      case _: IndexOutOfBoundsException => // Expected, so continue
    }
    

    If charAt throws IndexOutOfBoundsException as expected, control will transfer to the catch case, which does nothing. If, however, charAt fails to throw an exception, the next statement, fail(), will be run. The fail method always completes abruptly with a TestFailedException, thereby signaling a failed test.

    To make this common use case easier to express and read, ScalaTest provides two methods: assertThrows and intercept. Here's how you use assertThrows:

    val s = "hi"
    assertThrows[IndexOutOfBoundsException] { // Result type: Assertion
      s.charAt(-1)
    }
    

    This code behaves much like the previous example. If charAt throws an instance of IndexOutOfBoundsException, assertThrows will return Succeeded. But if charAt completes normally, or throws a different exception, assertThrows will complete abruptly with a TestFailedException.

    The intercept method behaves the same as assertThrows, except that instead of returning Succeeded, intercept returns the caught exception so that you can inspect it further if you wish. For example, you may need to ensure that data contained inside the exception have expected values. Here's an example:

    val s = "hi"
    val caught =
      intercept[IndexOutOfBoundsException] { // Result type: IndexOutOfBoundsException
        s.charAt(-1)
      }
    assert(caught.getMessage.indexOf("-1") != -1)
    

    Checking that a snippet of code does or does not compile

    Often when creating libraries you may wish to ensure that certain arrangements of code that represent potential “user errors” do not compile, so that your library is more error resistant. ScalaTest's Assertions trait includes the following syntax for that purpose:

    assertDoesNotCompile("val a: String = 1")
    

    If you want to ensure that a snippet of code does not compile because of a type error (as opposed to a syntax error), use:

    assertTypeError("val a: String = 1")
    

    Note that the assertTypeError call will only succeed if the given snippet of code does not compile because of a type error. A syntax error will still result on a thrown TestFailedException.

    If you want to state that a snippet of code does compile, you can make that more obvious with:

    assertCompiles("val a: Int = 1")
    

    Although the previous three constructs are implemented with macros that determine at compile time whether the snippet of code represented by the string does or does not compile, errors are reported as test failures at runtime.

    Assumptions

    Trait Assertions also provides methods that allow you to cancel a test. You would cancel a test if a resource required by the test was unavailable. For example, if a test requires an external database to be online, and it isn't, the test could be canceled to indicate it was unable to run because of the missing database. Such a test assumes a database is available, and you can use the assume method to indicate this at the beginning of the test, like this:

    assume(database.isAvailable)
    

    For each overloaded assert method, trait Assertions provides an overloaded assume method with an identical signature and behavior, except the assume methods throw TestCanceledException whereas the assert methods throw TestFailedException. As with assert, assume hides a Scala method in Predef that performs a similar function, but throws AssertionError. And just as you can with assert, you will get an error message extracted by a macro from the AST passed to assume, and can optionally provide a clue string to augment this error message. Here are some examples:

    assume(database.isAvailable, "The database was down again")
    assume(database.getAllUsers.count === 9)
    

    Forcing cancelations

    For each overloaded fail method, there's a corresponding cancel method with an identical signature and behavior, except the cancel methods throw TestCanceledException whereas the fail methods throw TestFailedException. Thus if you just need to cancel a test, you can write:

    cancel()
    

    If you want to cancel the test with a message, just place the message in the parentheses:

    cancel("Can't run the test because no internet connection was found")
    

    Getting a clue

    If you want more information that is provided by default by the methods if this trait, you can supply a "clue" string in one of several ways. The extra information (or "clues") you provide will be included in the detail message of the thrown exception. Both assert and assertResult provide a way for a clue to be included directly, intercept does not. Here's an example of clues provided directly in assert:

    assert(1 + 1 === 3, "this is a clue")
    

    and in assertResult:

    assertResult(3, "this is a clue") { 1 + 1 }
    

    The exceptions thrown by the previous two statements will include the clue string, "this is a clue", in the exception's detail message. To get the same clue in the detail message of an exception thrown by a failed intercept call requires using withClue:

    withClue("this is a clue") {
      intercept[IndexOutOfBoundsException] {
        "hi".charAt(-1)
      }
    }
    

    The withClue method will only prepend the clue string to the detail message of exception types that mix in the ModifiableMessage trait. See the documentation for ModifiableMessage for more information. If you wish to place a clue string after a block of code, see the documentation for AppendedClues.

    Note: ScalaTest's assertTypeError construct is in part inspired by the illTyped macro of shapeless.

  7. abstract class AsyncFeatureSpec extends AsyncFeatureSpecLike

    Permalink

    Enables testing of asynchronous code without blocking, using a style consistent with traditional FeatureSpec tests.

    Enables testing of asynchronous code without blocking, using a style consistent with traditional FeatureSpec tests.

    Recommended Usage: AsyncFeatureSpec is intended to enable users of FeatureSpec to write non-blocking asynchronous tests that are consistent with their traditional FeatureSpec tests. Note: AsyncFeatureSpec is intended for use in special situations where non-blocking asynchronous testing is needed, with class FeatureSpec used for general needs.

    Given a Future returned by the code you are testing, you need not block until the Future completes before performing assertions against its value. You can instead map those assertions onto the Future and return the resulting Future[Assertion] to ScalaTest. The test will complete asynchronously, when the Future[Assertion] completes.

    Although not required, FeatureSpec is often used together with GivenWhenThen to express acceptance requirements in more detail. Here's an example AsyncFeatureSpec:

    package org.scalatest.examples.asyncfeaturespec
    
    import org.scalatest._
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    case object IsOn
    case object PressPowerButton
    
    class TVSetActor { // Simulating an actor
      private var on: Boolean = false
      def !(msg: PressPowerButton.type): Unit =
        synchronized {
          on = !on
        }
      def ?(msg: IsOn.type)(implicit c: ExecutionContext): Future[Boolean] =
        Future {
          synchronized { on }
        }
    }
    
    class TVSetActorSpec extends AsyncFeatureSpec with GivenWhenThen {
    
      implicit override def executionContext =
        scala.concurrent.ExecutionContext.Implicits.global
    
      info("As a TV set owner")
      info("I want to be able to turn the TV on and off")
      info("So I can watch TV when I want")
      info("And save energy when I'm not watching TV")
    
      feature("TV power button") {
        scenario("User presses power button when TV is off") {
    
          Given("a TV set that is switched off")
          val tvSetActor = new TVSetActor
    
          When("the power button is pressed")
          tvSetActor ! PressPowerButton
    
          Then("the TV should switch on")
          val futureBoolean = tvSetActor ? IsOn
          futureBoolean map { isOn => assert(isOn) }
        }
    
        scenario("User presses power button when TV is on") {
    
          Given("a TV set that is switched on")
          val tvSetActor = new TVSetActor
          tvSetActor ! PressPowerButton
    
          When("the power button is pressed")
          tvSetActor ! PressPowerButton
    
          Then("the TV should switch off")
          val futureBoolean = tvSetActor ? IsOn
          futureBoolean map { isOn => assert(!isOn) }
        }
      }
    }
    

    Note: for more information on the calls to Given, When, and Then, see the documentation for trait GivenWhenThen and the Informers section below.

    An AsyncFeatureSpec contains feature clauses and scenarios. You define a feature clause with feature, and a scenario with scenario. Both feature and scenario are methods, defined in AsyncFeatureSpec, which will be invoked by the primary constructor of TVSetActorSpec. A feature clause describes a feature of the subject (class or other entity) you are specifying and testing. In the previous example, the subject under specification and test is a TV set. The feature being specified and tested is the behavior of a TV set when its power button is pressed. With each scenario you provide a string (the spec text) that specifies the behavior of the subject for one scenario in which the feature may be used, and a block of code that tests that behavior. You place the spec text between the parentheses, followed by the test code between curly braces. The test code will be wrapped up as a function passed as a by-name parameter to scenario, which will register the test for later execution. The result type of the by-name in an AsyncFeatureSpec must be Future[Assertion].

    Starting with version 3.0.0, ScalaTest assertions and matchers have result type Assertion. The result type of the first test in the example above, therefore, is Future[Assertion]. When an AsyncFeatureSpec is constructed, any test that results in Assertion will be implicitly converted to Future[Assertion] and registered. The implicit conversion is from Assertion to Future[Assertion] only, so you must end synchronous tests in some ScalaTest assertion or matcher expression. If a test would not otherwise end in type Assertion, you can place succeed at the end of the test. succeed, a field in trait Assertions, returns the Succeeded singleton:

    scala> succeed
    res2: org.scalatest.Assertion = Succeeded
    

    Thus placing succeed at the end of a test body will satisfy the type checker.

    An AsyncFeatureSpec's lifecycle has two phases: the registration phase and the ready phase. It starts in registration phase and enters ready phase the first time run is called on it. It then remains in ready phase for the remainder of its lifetime.

    Scenarios can only be registered with the scenario method while the AsyncFeatureSpec is in its registration phase. Any attempt to register a scenario after the AsyncFeatureSpec has entered its ready phase, i.e., after run has been invoked on the AsyncFeatureSpec, will be met with a thrown TestRegistrationClosedException. The recommended style of using AsyncFeatureSpec is to register tests during object construction as is done in all the examples shown here. If you keep to the recommended style, you should never see a TestRegistrationClosedException.

    Each scenario represents one test. The name of the test is the spec text passed to the scenario method. The feature name does not appear as part of the test name. In a AsyncFeatureSpec, therefore, you must take care to ensure that each test has a unique name (in other words, that each scenario has unique spec text).

    When you run a AsyncFeatureSpec, it will send Formatters in the events it sends to the Reporter. ScalaTest's built-in reporters will report these events in such a way that the output is easy to read as an informal specification of the subject being tested. For example, were you to run TVSetSpec from within the Scala interpreter:

    scala> org.scalatest.run(new TVSetActorSpec)
    

    You would see:

    TVSetActorSpec:
    As a TV set owner
    I want to be able to turn the TV on and off
    So I can watch TV when I want
    And save energy when I'm not watching TV
    Feature: TV power button
      Scenario: User presses power button when TV is off
        Given a TV set that is switched off
        When the power button is pressed
        Then the TV should switch on
      Scenario: User presses power button when TV is on
        Given a TV set that is switched on
        When the power button is pressed
        Then the TV should switch off
    

    Or, to run just the “Feature: TV power button Scenario: User presses power button when TV is on” method, you could pass that test's name, or any unique substring of the name, such as "TV is on". Here's an example:

    scala> org.scalatest.run(new TVSetActorSpec, "TV is on")
    TVSetActorSpec:
    As a TV set owner
    I want to be able to turn the TV on and off
    So I can watch TV when I want
    And save energy when I'm not watching TV
    Feature: TV power button
      Scenario: User presses power button when TV is on
        Given a TV set that is switched on
        When the power button is pressed
        Then the TV should switch off
    

    Asynchronous execution model

    AsyncFeatureSpec extends AsyncTestSuite, which provides an implicit scala.concurrent.ExecutionContext named executionContext. This execution context is used by AsyncFeatureSpec to transform the Future[Assertion]s returned by each test into the FutureOutcome returned by the test function passed to withFixture. This ExecutionContext is also intended to be used in the tests, including when you map assertions onto futures.

    On both the JVM and Scala.js, the default execution context provided by ScalaTest's asynchronous testing styles confines execution to a single thread per test. On JavaScript, where single-threaded execution is the only possibility, the default execution context is scala.scalajs.concurrent.JSExecutionContext.Implicits.queue. On the JVM, the default execution context is a serial execution context provided by ScalaTest itself.

    When ScalaTest's serial execution context is called upon to execute a task, that task is recorded in a queue for later execution. For example, one task that will be placed in this queue is the task that transforms the Future[Assertion] returned by an asynchronous test body to the FutureOutcome returned from the test function. Other tasks that will be queued are any transformations of, or callbacks registered on, Futures that occur in your test body, including any assertions you map onto Futures. Once the test body returns, the thread that executed the test body will execute the tasks in that queue one after another, in the order they were enqueued.

    ScalaTest provides its serial execution context as the default on the JVM for three reasons. First, most often running both tests and suites in parallel does not give a significant performance boost compared to just running suites in parallel. Thus parallel execution of Future transformations within individual tests is not generally needed for performance reasons.

    Second, if multiple threads are operating in the same suite concurrently, you'll need to make sure access to any mutable fixture objects by multiple threads is synchronized. Although access to mutable state along the same linear chain of Future transformations need not be synchronized, this does not hold true for callbacks, and in general it is easy to make a mistake. Simply put: synchronizing access to shared mutable state is difficult and error prone. Because ScalaTest's default execution context on the JVM confines execution of Future transformations and call backs to a single thread, you need not (by default) worry about synchronizing access to mutable state in your asynchronous-style tests.

    Third, asynchronous-style tests need not be complete when the test body returns, because the test body returns a Future[Assertion]. This Future[Assertion] will often represent a test that has not yet completed. As a result, when using a more traditional execution context backed by a thread-pool, you could potentially start many more tests executing concurrently than there are threads in the thread pool. The more concurrently execute tests you have competing for threads from the same limited thread pool, the more likely it will be that tests will intermitently fail due to timeouts.

    Using ScalaTest's serial execution context on the JVM will ensure the same thread that produced the Future[Assertion] returned from a test body is also used to execute any tasks given to the execution context while executing the test body—and that thread will not be allowed to do anything else until the test completes. If the serial execution context's task queue ever becomes empty while the Future[Assertion] returned by that test's body has not yet completed, the thread will block until another task for that test is enqueued. Although it may seem counter-intuitive, this blocking behavior means the total number of tests allowed to run concurrently will be limited to the total number of threads executing suites. This fact means you can tune the thread pool such that maximum performance is reached while avoiding (or at least, reducing the likelihood of) tests that fail due to timeouts because of thread competition.

    This thread confinement strategy does mean, however, that when you are using the default execution context on the JVM, you must be sure to never block in the test body waiting for a task to be completed by the execution context. If you block, your test will never complete. This kind of problem will be obvious, because the test will consistently hang every time you run it. (If a test is hanging, and you're not sure which one it is, enable slowpoke notifications.) If you really do want to block in your tests, you may wish to just use a traditional FeatureSpec with ScalaFutures instead. Alternatively, you could override the executionContext and use a traditional ExecutionContext backed by a thread pool. This will enable you to block in an asynchronous-style test on the JVM, but you'll need to worry about synchronizing access to shared mutable state.

    To use a different execution context, just override executionContext. For example, if you prefer to use the runNow execution context on Scala.js instead of the default queue, you would write:

    // on Scala.js
    implicit override def executionContext =
        scala.scalajs.concurrent.JSExecutionContext.Implicits.runNow
    

    If you prefer on the JVM to use the global execution context, which is backed by a thread pool, instead of ScalaTest's default serial execution contex, which confines execution to a single thread, you would write:

    // on the JVM (and also compiles on Scala.js, giving
    // you the queue execution context)
    implicit override def executionContext =
        scala.concurrent.ExecutionContext.Implicits.global
    

    Serial and parallel test execution

    By default (unless you mix in ParallelTestExecution), tests in an AsyncFeatureSpec will be executed one after another, i.e., serially. This is true whether those tests return Assertion or Future[Assertion], no matter what threads are involved. This default behavior allows you to re-use a shared fixture, such as an external database that needs to be cleaned after each test, in multiple tests in async-style suites. This is implemented by registering each test, other than the first test, to run as a continuation after the previous test completes.

    If you want the tests of an AsyncFeatureSpec to be executed in parallel, you must mix in ParallelTestExecution and enable parallel execution of tests in your build. You enable parallel execution in Runner with the -P command line flag. In the ScalaTest Maven Plugin, set parallel to true. In sbt, parallel execution is the default, but to be explicit you can write:

    parallelExecution in Test := true // the default in sbt
    

    On the JVM, if both ParallelTestExecution is mixed in and parallel execution is enabled in the build, tests in an async-style suite will be started in parallel, using threads from the Distributor, and allowed to complete in parallel, using threads from the executionContext. If you are using ScalaTest's serial execution context, the JVM default, asynchronous tests will run in parallel very much like traditional (such as FeatureSpec) tests run in parallel: 1) Because ParallelTestExecution extends OneInstancePerTest, each test will run in its own instance of the test class, you need not worry about synchronizing access to mutable instance state shared by different tests in the same suite. 2) Because the serial execution context will confine the execution of each test to the single thread that executes the test body, you need not worry about synchronizing access to shared mutable state accessed by transformations and callbacks of Futures inside the test.

    If ParallelTestExecution is mixed in but parallel execution of suites is not enabled, asynchronous tests on the JVM will be started sequentially, by the single thread that invoked run, but without waiting for one test to complete before the next test is started. As a result, asynchronous tests will be allowed to complete in parallel, using threads from the executionContext. If you are using the serial execution context, however, you'll see the same behavior you see when parallel execution is disabled and a traditional suite that mixes in ParallelTestExecution is executed: the tests will run sequentially. If you use an execution context backed by a thread-pool, such as global, however, even though tests will be started sequentially by one thread, they will be allowed to run concurrently using threads from the execution context's thread pool.

    The latter behavior is essentially what you'll see on Scala.js when you execute a suite that mixes in ParallelTestExecution. Because only one thread exists when running under JavaScript, you can't "enable parallel execution of suites." However, it may still be useful to run tests in parallel on Scala.js, because tests can invoke API calls that are truly asynchronous by calling into external APIs that take advantage of non-JavaScript threads. Thus on Scala.js, ParallelTestExecution allows asynchronous tests to run in parallel, even though they must be started sequentially. This may give you better performance when you are using API calls in your Scala.js tests that are truly asynchronous.

    Futures and expected exceptions

    If you need to test for expected exceptions in the context of futures, you can use the recoverToSucceededIf and recoverToExceptionIf methods of trait RecoverMethods. Because this trait is mixed into supertrait AsyncTestSuite, both of these methods are available by default in an AsyncFeatureSpec.

    If you just want to ensure that a future fails with a particular exception type, and do not need to inspect the exception further, use recoverToSucceededIf:

    recoverToSucceededIf[IllegalStateException] { // Result type: Future[Assertion]
      emptyStackActor ? Peek
    }
    

    The recoverToSucceededIf method performs a job similar to assertThrows, except in the context of a future. It transforms a Future of any type into a Future[Assertion] that succeeds only if the original future fails with the specified exception. Here's an example in the REPL:

    scala> import org.scalatest.RecoverMethods._
    import org.scalatest.RecoverMethods._
    
    scala> import scala.concurrent.Future
    import scala.concurrent.Future
    
    scala> import scala.concurrent.ExecutionContext.Implicits.global
    import scala.concurrent.ExecutionContext.Implicits.global
    
    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { throw new IllegalStateException }
         | }
    res0: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res0.value
    res1: Option[scala.util.Try[org.scalatest.Assertion]] = Some(Success(Succeeded))
    

    Otherwise it fails with an error message similar to those given by assertThrows:

    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { throw new RuntimeException }
         | }
    res2: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res2.value
    res3: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: Expected exception
          java.lang.IllegalStateException to be thrown, but java.lang.RuntimeException
          was thrown))
    
    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { 42 }
         | }
    res4: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res4.value
    res5: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: Expected exception
          java.lang.IllegalStateException to be thrown, but no exception was thrown))
    

    The recoverToExceptionIf method differs from the recoverToSucceededIf in its behavior when the assertion succeeds: recoverToSucceededIf yields a Future[Assertion], whereas recoverToExceptionIf yields a Future[T], where T is the expected exception type.

    recoverToExceptionIf[IllegalStateException] { // Result type: Future[IllegalStateException]
      emptyStackActor ? Peek
    }
    

    In other words, recoverToExpectionIf is to intercept as recovertToSucceededIf is to assertThrows. The first one allows you to perform further assertions on the expected exception. The second one gives you a result type that will satisfy the type checker at the end of the test body. Here's an example showing recoverToExceptionIf in the REPL:

    scala> val futureEx =
         |   recoverToExceptionIf[IllegalStateException] {
         |     Future { throw new IllegalStateException("hello") }
         |   }
    futureEx: scala.concurrent.Future[IllegalStateException] = ...
    
    scala> futureEx.value
    res6: Option[scala.util.Try[IllegalStateException]] =
        Some(Success(java.lang.IllegalStateException: hello))
    
    scala> futureEx map { ex => assert(ex.getMessage == "world") }
    res7: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res7.value
    res8: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: "[hello]" did not equal "[world]"))
    

    Ignored tests

    To support the common use case of temporarily disabling a test, with the good intention of resurrecting the test at a later time, AsyncFeatureSpec provides registration methods that start with ignore instead of scenario. Here's an example:

    package org.scalatest.examples.asyncfeaturespec.ignore
    
    import org.scalatest.AsyncFeatureSpec
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFeatureSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
      def addNow(addends: Int*): Int = addends.sum
    
      feature("The add methods") {
    
        ignore("addSoon will eventually compute a sum of passed Ints") {
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
    
        scenario("addNow will immediately compute a sum of passed Ints") {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    If you run class AddSpec with:

    scala> org.scalatest.run(new AddSpec)
    

    It will run only the second test and report that the first test was ignored:

    AddSpec:
    Feature: The add methods
    - Scenario: addSoon will eventually compute a sum of passed Ints !!! IGNORED !!!
    - Scenario: addNow will immediately compute a sum of passed Ints
    
    

    If you wish to temporarily ignore an entire suite of tests, you can (on the JVM, not Scala.js) annotate the test class with @Ignore, like this:

    package org.scalatest.examples.asyncfeaturespec.ignoreall
    
    import org.scalatest.AsyncFeatureSpec
    import scala.concurrent.Future
    import org.scalatest.Ignore
    
    @Ignore
    class AddSpec extends AsyncFeatureSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
      def addNow(addends: Int*): Int = addends.sum
    
      feature("The add methods") {
    
        scenario("addSoon will eventually compute a sum of passed Ints") {
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
    
        scenario("addNow will immediately compute a sum of passed Ints") {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    When you mark a test class with a tag annotation, ScalaTest will mark each test defined in that class with that tag. Thus, marking the AddSpec in the above example with the @Ignore tag annotation means that both tests in the class will be ignored. If you run the above AddSpec in the Scala interpreter, you'll see:

    AddSpec:
    Feature: The add methods
    - Scenario: addSoon will eventually compute a sum of passed Ints !!! IGNORED !!!
    - Scenario: addNow will immediately compute a sum of passed Ints !!! IGNORED !!!
    

    Note that marking a test class as ignored won't prevent it from being discovered by ScalaTest. Ignored classes will be discovered and run, and all their tests will be reported as ignored. This is intended to keep the ignored class visible, to encourage the developers to eventually fix and “un-ignore” it. If you want to prevent a class from being discovered at all (on the JVM, not Scala.js), use the DoNotDiscover annotation instead.

    If you want to ignore all tests of a suite on Scala.js, where annotations can't be inspected at runtime, you'll need to change it to ignore at each test site. To make a suite non-discoverable on Scala.js, ensure it does not declare a public no-arg constructor. You can either declare a public constructor that takes one or more arguments, or make the no-arg constructor non-public. Because this technique will also make the suite non-discoverable on the JVM, it is a good approach for suites you want to run (but not be discoverable) on both Scala.js and the JVM.

    Informers

    One of the parameters to AsyncFeatureSpec's run method is a Reporter, which will collect and report information about the running suite of tests. Information about suites and tests that were run, whether tests succeeded or failed, and tests that were ignored will be passed to the Reporter as the suite runs. Most often the default reporting done by AsyncFeatureSpec's methods will be sufficient, but occasionally you may wish to provide custom information to the Reporter from a test. For this purpose, an Informer that will forward information to the current Reporter is provided via the info parameterless method. You can pass the extra information to the Informer via its apply method. The Informer will then pass the information to the Reporter via an InfoProvided event.

    One use case for the Informer is to pass more information about a scenario to the reporter. For example, the GivenWhenThen trait provides methods that use the implicit info provided by AsyncFeatureSpec to pass such information to the reporter. You can see this in action in the initial example of this trait's documentation.

    Documenters

    AsyncFeatureSpec also provides a markup method that returns a Documenter, which allows you to send to the Reporter text formatted in Markdown syntax. You can pass the extra information to the Documenter via its apply method. The Documenter will then pass the information to the Reporter via an MarkupProvided event.

    Here's an example FlatSpec that uses markup:

    package org.scalatest.examples.asyncfeaturespec.markup
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends AsyncFeatureSpec with GivenWhenThen {
    
      markup { """
    
    Mutable Set
    -----------
    
    A set is a collection that contains no duplicate elements.
    
    To implement a concrete mutable set, you need to provide implementations
    of the following methods:
    
        def contains(elem: A): Boolean
        def iterator: Iterator[A]
        def += (elem: A): this.type
        def -= (elem: A): this.type
    
    If you wish that methods like `take`,
    `drop`, `filter` return the same kind of set,
    you should also override:
    
         def empty: This
    
    It is also good idea to override methods `foreach` and
    `size` for efficiency.
    
      """ }
    
      feature("An element can be added to an empty mutable Set") {
        scenario("When an element is added to an empty mutable Set") {
          Given("an empty mutable Set")
          val set = mutable.Set.empty[String]
    
          When("an element is added")
          set += "clarity"
    
          Then("the Set should have size 1")
          assert(set.size === 1)
    
          And("the Set should contain the added element")
          assert(set.contains("clarity"))
    
          markup("This test finished with a **bold** statement!")
          succeed
        }
      }
    }
    

    Although all of ScalaTest's built-in reporters will display the markup text in some form, the HTML reporter will format the markup information into HTML. Thus, the main purpose of markup is to add nicely formatted text to HTML reports. Here's what the above SetSpec would look like in the HTML reporter:

    Notifiers and alerters

    ScalaTest records text passed to info and markup during tests, and sends the recorded text in the recordedEvents field of test completion events like TestSucceeded and TestFailed. This allows string reporters (like the standard out reporter) to show info and markup text after the test name in a color determined by the outcome of the test. For example, if the test fails, string reporters will show the info and markup text in red. If a test succeeds, string reporters will show the info and markup text in green. While this approach helps the readability of reports, it means that you can't use info to get status updates from long running tests.

    To get immediate (i.e., non-recorded) notifications from tests, you can use note (a Notifier) and alert (an Alerter). Here's an example showing the differences:

    package org.scalatest.examples.asyncfeaturespec.note
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends AsyncFeatureSpec {
    
      feature("An element can be added to an empty mutable Set") {
        scenario("When an element is added to an empty mutable Set") {
    
          info("info is recorded")
          markup("markup is *also* recorded")
          note("notes are sent immediately")
          alert("alerts are also sent immediately")
    
          val set = mutable.Set.empty[String]
          set += "clarity"
          assert(set.size === 1)
          assert(set.contains("clarity"))
        }
      }
    }
    

    Because note and alert information is sent immediately, it will appear before the test name in string reporters, and its color will be unrelated to the ultimate outcome of the test: note text will always appear in green, alert text will always appear in yellow. Here's an example:

    scala> org.scalatest.run(new SetSpec)
    SetSpec:
    Feature: An element can be added to an empty mutable Set
      + notes are sent immediately
      + alerts are also sent immediately
      Scenario: When an element is added to an empty mutable Set
        info is recorded
      + markup is *also* recorded
    

    Another example is slowpoke notifications. If you find a test is taking a long time to complete, but you're not sure which test, you can enable slowpoke notifications. ScalaTest will use an Alerter to fire an event whenever a test has been running longer than a specified amount of time.

    In summary, use info and markup for text that should form part of the specification output. Use note and alert to send status notifications. (Because the HTML reporter is intended to produce a readable, printable specification, info and markup text will appear in the HTML report, but note and alert text will not.)

    Pending tests

    A pending test is one that has been given a name but is not yet implemented. The purpose of pending tests is to facilitate a style of testing in which documentation of behavior is sketched out before tests are written to verify that behavior (and often, before the behavior of the system being tested is itself implemented). Such sketches form a kind of specification of what tests and functionality to implement later.

    To support this style of testing, a test can be given a name that specifies one bit of behavior required by the system being tested. At the end of the test, it can call method pending, which will cause it to complete abruptly with TestPendingException.

    Because tests in ScalaTest can be designated as pending with TestPendingException, both the test name and any information sent to the reporter when running the test can appear in the report of a test run. (In other words, the code of a pending test is executed just like any other test.) However, because the test completes abruptly with TestPendingException, the test will be reported as pending, to indicate the actual test, and possibly the functionality, has not yet been implemented. Here's an example:

    package org.scalatest.examples.asyncfeaturespec.pending
    
    import org.scalatest.AsyncFeatureSpec
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFeatureSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
      def addNow(addends: Int*): Int = addends.sum
    
      feature("The add methods") {
    
        scenario("addSoon will eventually compute a sum of passed Ints") (pending)
    
        scenario("addNow will immediately compute a sum of passed Ints") {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    (Note: "(pending)" is the body of the test. Thus the test contains just one statement, an invocation of the pending method, which throws TestPendingException.) If you run this version of AddSpec with:

    scala> org.scalatest.run(new AddSpec)
    

    It will run both tests, but report that first test is pending. You'll see:

    AddSpec:
    Feature: The add methods
    - Scenario: addSoon will eventually compute a sum of passed Ints (pending)
    - Scenario: addNow will immediately compute a sum of passed Ints
    

    One difference between an ignored test and a pending one is that an ignored test is intended to be used during significant refactorings of the code under test, when tests break and you don't want to spend the time to fix all of them immediately. You can mark some of those broken tests as ignored temporarily, so that you can focus the red bar on just failing tests you actually want to fix immediately. Later you can go back and fix the ignored tests. In other words, by ignoring some failing tests temporarily, you can more easily notice failed tests that you actually want to fix. By contrast, a pending test is intended to be used before a test and/or the code under test is written. Pending indicates you've decided to write a test for a bit of behavior, but either you haven't written the test yet, or have only written part of it, or perhaps you've written the test but don't want to implement the behavior it tests until after you've implemented a different bit of behavior you realized you need first. Thus ignored tests are designed to facilitate refactoring of existing code whereas pending tests are designed to facilitate the creation of new code.

    One other difference between ignored and pending tests is that ignored tests are implemented as a test tag that is excluded by default. Thus an ignored test is never executed. By contrast, a pending test is implemented as a test that throws TestPendingException (which is what calling the pending method does). Thus the body of pending tests are executed up until they throw TestPendingException.

    Tagging tests

    An AsyncFeatureSpec's tests may be classified into groups by tagging them with string names. As with any suite, when executing an AsyncFeatureSpec, groups of tests can optionally be included and/or excluded. To tag an AsyncFeatureSpec's tests, you pass objects that extend class org.scalatest.Tag to methods that register tests. Class Tag takes one parameter, a string name. If you have created tag annotation interfaces as described in the Tag documentation, then you will probably want to use tag names on your test functions that match. To do so, simply pass the fully qualified names of the tag interfaces to the Tag constructor. For example, if you've defined a tag annotation interface with fully qualified name, com.mycompany.tags.DbTest, then you could create a matching tag for AsyncFeatureSpecs like this:

    package org.scalatest.examples.asyncfeaturespec.tagging
    
    import org.scalatest.Tag
    
    object DbTest extends Tag("com.mycompany.tags.DbTest")
    

    Given these definitions, you could place AsyncFeatureSpec tests into groups with tags like this:

    import org.scalatest.AsyncFeatureSpec
    import org.scalatest.tagobjects.Slow
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFeatureSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
      def addNow(addends: Int*): Int = addends.sum
    
      feature("The add methods") {
    
        scenario("addSoon will eventually compute a sum of passed Ints",
             Slow) {
    
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
    
        scenario("addNow will immediately compute a sum of passed Ints",
            Slow, DbTest) {
    
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    This code marks both tests with the org.scalatest.tags.Slow tag, and the second test with the com.mycompany.tags.DbTest tag.

    The run method takes a Filter, whose constructor takes an optional Set[String] called tagsToInclude and a Set[String] called tagsToExclude. If tagsToInclude is None, all tests will be run except those those belonging to tags listed in the tagsToExclude Set. If tagsToInclude is defined, only tests belonging to tags mentioned in the tagsToInclude set, and not mentioned in tagsToExclude, will be run.

    It is recommended, though not required, that you create a corresponding tag annotation when you create a Tag object. A tag annotation (on the JVM, not Scala.js) allows you to tag all the tests of an AsyncFeatureSpec in one stroke by annotating the class. For more information and examples, see the documentation for class Tag. On Scala.js, to tag all tests of a suite, you'll need to tag each test individually at the test site.

    Shared fixtures

    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.

    ScalaTest recommends three techniques to eliminate such code duplication in async styles:

    • Refactor using Scala
    • Override withFixture
    • Mix in a before-and-after trait

    Each technique is geared towards helping you reduce code duplication without introducing instance vars, shared mutable objects, or other dependencies between tests. Eliminating shared mutable state across tests will make your test code easier to reason about and eliminate the need to synchronize access to shared mutable state on the JVM.

    The following sections describe these techniques, including explaining the recommended usage for each. But first, here's a table summarizing the options:

    Refactor using Scala when different tests need different fixtures.
    get-fixture methods The extract method refactor helps you create a fresh instances of mutable fixture objects in each test that needs them, but doesn't help you clean them up when you're done.
    loan-fixture methods Factor out dupicate code with the loan pattern when different tests need different fixtures that must be cleaned up afterwards.
    Override withFixture when most or all tests need the same fixture.
    withFixture(NoArgAsyncTest) The recommended default approach when most or all tests need the same fixture treatment. This general technique allows you, for example, to perform side effects at the beginning and end of all or most tests, transform the outcome of tests, retry tests, make decisions based on test names, tags, or other test data. Use this technique unless:
    Different tests need different fixtures (refactor using Scala instead)
    An exception in fixture code should abort the suite, not fail the test (use a before-and-after trait instead)
    You have objects to pass into tests (override withFixture(OneArgAsyncTest) instead)
    withFixture(OneArgAsyncTest) Use when you want to pass the same fixture object or objects as a parameter into all or most tests.
    Mix in a before-and-after trait when you want an aborted suite, not a failed test, if the fixture code fails.
    BeforeAndAfter Use this boilerplate-buster when you need to perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.
    BeforeAndAfterEach Use when you want to stack traits that perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.

    Calling get-fixture methods

    If you need to create the same mutable fixture objects in multiple tests, and don't need to clean them up after using them, the simplest approach is to write one or more get-fixture methods. A get-fixture method returns a new instance of a needed fixture object (or a holder object containing multiple fixture objects) each time it is called. You can call a get-fixture method at the beginning of each test that needs the fixture, storing the returned object or objects in local variables. Here's an example:

    package org.scalatest.examples.asyncfeaturespec.getfixture
    
    import org.scalatest.AsyncFeatureSpec
    import scala.concurrent.Future
    
    class ExampleSpec extends AsyncFeatureSpec {
    
      def fixture: Future[String] = Future { "ScalaTest is designed to " }
    
      feature("Simplicity") {
        scenario("User needs to read test code written by others") {
          val future = fixture
          val result = future map { s => s + "encourage clear code!" }
          result map { s =>
            assert(s == "ScalaTest is designed to encourage clear code!")
          }
        }
    
        scenario("User needs to understand what the tests are doing") {
          val future = fixture
          val result = future map { s => s + "be easy to reason about!" }
          result map { s =>
            assert(s == "ScalaTest is designed to be easy to reason about!")
          }
        }
      }
    }
    

    If you need to configure fixture objects differently in different tests, you can pass configuration into the get-fixture method. For example, you could pass in an initial value for a fixture object as a parameter to the get-fixture method.

    Overriding withFixture(NoArgAsyncTest)

    Although the get-fixture method approach takes care of setting up a fixture at the beginning of each test, it doesn't address the problem of cleaning up a fixture at the end of the test. If you just need to perform a side-effect at the beginning or end of a test, and don't need to actually pass any fixture objects into the test, you can override withFixture(NoArgAsyncTest), a method defined in trait AsyncTestSuite, a supertrait of AsyncFeatureSpec.

    Trait AsyncFeatureSpec's runTest method passes a no-arg async test function to withFixture(NoArgAsyncTest). It is withFixture's responsibility to invoke that test function. The default implementation of withFixture simply invokes the function and returns the result, like this:

    // Default implementation in trait AsyncTestSuite
    protected def withFixture(test: NoArgAsyncTest): FutureOutcome = {
      test()
    }
    

    You can, therefore, override withFixture to perform setup before invoking the test function, and/or perform cleanup after the test completes. The recommended way to ensure cleanup is performed after a test completes is to use the complete-lastly syntax, defined in supertrait CompleteLastly. The complete-lastly syntax will ensure that cleanup will occur whether future-producing code completes abruptly by throwing an exception, or returns normally yielding a future. In the latter case, complete-lastly will register the cleanup code to execute asynchronously when the future completes.

    The withFixture method is designed to be stacked, and to enable this, you should always call the super implementation of withFixture, 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)”, like this:

    // Your implementation
    override def withFixture(test: NoArgTest) = {
    
      // Perform setup here
    
      complete {
        super.withFixture(test) // Invoke the test function
      } lastly {
        // Perform cleanup here
      }
    }
    

    If you have no cleanup to perform, you can write withFixture like this instead:

    // Your implementation
    override def withFixture(test: NoArgTest) = {
    
      // Perform setup here
    
      super.withFixture(test) // Invoke the test function
    }
    

    If you want to perform an action only for certain outcomes, you'll need to register code performing that action as a callback on the Future using one of Future's registration methods: onComplete, onSuccess, or onFailure. Note that if a test fails, that will be treated as a scala.util.Success(org.scalatest.Failed). So if you want to perform an action if a test fails, for example, you'd register the callback using onSuccess.

    Here's an example in which withFixture(NoArgAsyncTest) is used to take a snapshot of the working directory if a test fails, and send that information to the standard output stream:

    package org.scalatest.examples.asyncfeaturespec.noargasynctest
    
    import java.io.File
    import org.scalatest._
    import scala.concurrent.Future
    
    class ExampleSpec extends AsyncFeatureSpec {
    
      override def withFixture(test: NoArgAsyncTest) = {
    
        super.withFixture(test) onFailedThen { _ =>
          val currDir = new File(".")
          val fileNames = currDir.list()
          info("Dir snapshot: " + fileNames.mkString(", "))
        }
      }
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      feature("addSoon") {
        scenario("succeed case") {
          addSoon(1, 1) map { sum => assert(sum == 2) }
        }
    
        scenario("fail case") {
          addSoon(1, 1) map { sum => assert(sum == 3) }
        }
      }
    }
    

    Running this version of ExampleSpec in the interpreter in a directory with two files, hello.txt and world.txt would give the following output:

    scala> org.scalatest.run(new ExampleSpec)
    ExampleSpec:
    Feature: addSoon
    - Scenario: succeed case
    - Scenario: fail case *** FAILED ***
      2 did not equal 3 (:33)
    

    Note that the NoArgAsyncTest passed to withFixture, in addition to an apply method that executes the test, also includes the test name and the config map passed to runTest. Thus you can also use the test name and configuration objects in your withFixture implementation.

    Lastly, if you want to transform the outcome in some way in withFixture, you'll need to use either the map or transform methods of Future, like this:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      val futureOutcome = super.withFixture(test) // Invoke the test function
    
      futureOutcome change { outcome =>
        // transform the outcome into a new outcome here
      }
    }
    

    Note that a NoArgAsyncTest's apply method will return a scala.util.Failure only if the test completes abruptly with a "test-fatal" exception (such as OutOfMemoryError) that should cause the suite to abort rather than the test to fail. Thus usually you would use map to transform future outcomes, not transform, so that such test-fatal exceptions pass through unchanged. The suite will abort asynchronously with any exception returned from NoArgAsyncTest's apply method in a scala.util.Failure.

    Calling loan-fixture methods

    If you need to both pass a fixture object into a test and perform cleanup at the end of the test, you'll need to use the loan pattern. If different tests need different fixtures that require cleanup, you can implement the loan pattern directly by writing loan-fixture methods. A loan-fixture method takes a function whose body forms part or all of a test's code. It creates a fixture, passes it to the test code by invoking the function, then cleans up the fixture after the function returns.

    The following example shows three tests that use two fixtures, a database and a file. Both require cleanup after, so each is provided via a loan-fixture method. (In this example, the database is simulated with a StringBuffer.)

    package org.scalatest.examples.asyncfeaturespec.loanfixture
    
    import java.util.concurrent.ConcurrentHashMap
    
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    object DbServer { // Simulating a database server
      type Db = StringBuffer
      private final val databases = new ConcurrentHashMap[String, Db]
      def createDb(name: String): Db = {
        val db = new StringBuffer // java.lang.StringBuffer is thread-safe
        databases.put(name, db)
        db
      }
      def removeDb(name: String): Unit = {
        databases.remove(name)
      }
    }
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    import org.scalatest._
    import DbServer._
    import java.util.UUID.randomUUID
    
    class ExampleSpec extends AsyncFeatureSpec {
    
      def withDatabase(testCode: Future[Db] => Future[Assertion]) = {
        val dbName = randomUUID.toString // generate a unique db name
        val futureDb = Future { createDb(dbName) } // create the fixture
        complete {
          val futurePopulatedDb =
            futureDb map { db =>
              db.append("ScalaTest is designed to ") // perform setup
            }
          testCode(futurePopulatedDb) // "loan" the fixture to the test code
        } lastly {
          removeDb(dbName) // ensure the fixture will be cleaned up
        }
      }
    
      def withActor(testCode: StringActor => Future[Assertion]) = {
        val actor = new StringActor
        complete {
          actor ! Append("ScalaTest is designed to ") // set up the fixture
          testCode(actor) // "loan" the fixture to the test code
        } lastly {
          actor ! Clear // ensure the fixture will be cleaned up
        }
      }
    
      feature("Simplicity") {
        // This test needs the actor fixture
        scenario("User needs to read test code written by others") {
          withActor { actor =>
            actor ! Append("encourage clear code!")
            val futureString = actor ? GetValue
            futureString map { s =>
              assert(s === "ScalaTest is designed to encourage clear code!")
            }
          }
        }
        // This test needs the database fixture
        scenario("User needs to understand what the tests are doing") {
          withDatabase { futureDb =>
            futureDb map { db =>
              db.append("be easy to reason about!")
              assert(db.toString === "ScalaTest is designed to be easy to reason about!")
            }
          }
        }
        // This test needs both the actor and the database
        scenario("User needs to write tests") {
          withDatabase { futureDb =>
            withActor { actor => // loan-fixture methods compose
              actor ! Append("be easy to remember how to write!")
              val futureString = actor ? GetValue
              val futurePair: Future[(Db, String)] =
                futureDb zip futureString
              futurePair map { case (db, s) =>
                db.append("be easy to learn!")
                assert(db.toString === "ScalaTest is designed to be easy to learn!")
                assert(s === "ScalaTest is designed to be easy to remember how to write!")
              }
            }
          }
        }
      }
    }
    

    As demonstrated by the last test, loan-fixture methods compose. Not only do loan-fixture methods allow you to give each test the fixture it needs, they allow you to give a test multiple fixtures and clean everything up afterwards.

    Also demonstrated in this example is the technique of giving each test its own "fixture sandbox" to play in. When your fixtures involve external side-effects, like creating databases, it is a good idea to give each database a unique name as is done in this example. This keeps tests completely isolated, allowing you to run them in parallel if desired.

    Overriding withFixture(OneArgTest)

    If all or most tests need the same fixture, you can avoid some of the boilerplate of the loan-fixture method approach by using a fixture.AsyncTestSuite and overriding withFixture(OneArgAsyncTest). Each test in a fixture.AsyncTestSuite takes a fixture as a parameter, allowing you to pass the fixture into the test. You must indicate the type of the fixture parameter by specifying FixtureParam, and implement a withFixture method that takes a OneArgAsyncTest. This withFixture method is responsible for invoking the one-arg async test function, so you can perform fixture set up before invoking and passing the fixture into the test function, and ensure clean up is performed after the test completes.

    To enable the stacking of traits that define withFixture(NoArgAsyncTest), it is a good idea to let withFixture(NoArgAsyncTest) invoke the test function instead of invoking the test function directly. To do so, you'll need to convert the OneArgAsyncTest to a NoArgAsyncTest. You can do that by passing the fixture object to the toNoArgAsyncTest method of OneArgAsyncTest. In other words, instead of writing “test(theFixture)”, you'd delegate responsibility for invoking the test function to the withFixture(NoArgAsyncTest) method of the same instance by writing:

    withFixture(test.toNoArgAsyncTest(theFixture))
    

    Here's a complete example:

    package org.scalatest.examples.asyncfeaturespec.oneargasynctest
    
    import org.scalatest._
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class ExampleSpec extends fixture.AsyncFeatureSpec {
    
      type FixtureParam = StringActor
    
      def withFixture(test: OneArgAsyncTest): FutureOutcome = {
    
        val actor = new StringActor
        complete {
          actor ! Append("ScalaTest is designed to ") // set up the fixture
          withFixture(test.toNoArgAsyncTest(actor))
        } lastly {
          actor ! Clear // ensure the fixture will be cleaned up
        }
      }
    
      feature("Simplicity") {
        scenario("User needs to read test code written by others") { actor =>
          actor ! Append("encourage clear code!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s === "ScalaTest is designed to encourage clear code!")
          }
        }
    
        scenario("User needs to understand what the tests are doing") { actor =>
          actor ! Append("be easy to reason about!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s === "ScalaTest is designed to be easy to reason about!")
          }
        }
      }
    }
    

    In this example, the tests required one fixture object, a StringActor. If your tests need multiple fixture objects, you can simply define the FixtureParam type to be a tuple containing the objects or, alternatively, a case class containing the objects. For more information on the withFixture(OneArgAsyncTest) technique, see the documentation for fixture.AsyncFeatureSpec.

    Mixing in BeforeAndAfter

    In all the shared fixture examples shown so far, the activities of creating, setting up, and cleaning up the fixture objects have been performed during the test. This means that if an exception occurs during any of these activities, it will be reported as a test failure. Sometimes, however, you may want setup to happen before the test starts, and cleanup after the test has completed, so that if an exception occurs during setup or cleanup, the entire suite aborts and no more tests are attempted. The simplest way to accomplish this in ScalaTest is to mix in trait BeforeAndAfter. With this trait you can denote a bit of code to run before each test with before and/or after each test each test with after, like this:

    package org.scalatest.examples.asyncfeaturespec.beforeandafter
    
    import org.scalatest.AsyncFeatureSpec
    import org.scalatest.BeforeAndAfter
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class ExampleSpec extends AsyncFeatureSpec with BeforeAndAfter {
    
      final val actor = new StringActor
    
      before {
        actor ! Append("ScalaTest is designed to ") // set up the fixture
      }
    
      after {
        actor ! Clear // clean up the fixture
      }
    
      feature("Simplicity") {
        scenario("User needs to read test code written by others") {
          actor ! Append("encourage clear code!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is designed to encourage clear code!")
          }
        }
    
        scenario("User needs to understand what the tests are doing") {
          actor ! Append("be easy to reason about!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is designed to be easy to reason about!")
          }
        }
      }
    }
    

    Note that the only way before and after code can communicate with test code is via some side-effecting mechanism, commonly by reassigning instance vars or by changing the state of mutable objects held from instance vals (as in this example). If using instance vars or mutable objects held from instance vals you wouldn't be able to run tests in parallel in the same instance of the test class (on the JVM, not Scala.js) unless you synchronized access to the shared, mutable state.

    Note that on the JVM, if you override ScalaTest's default serial execution context, you will likely need to worry about synchronizing access to shared mutable fixture state, because the execution context may assign different threads to process different Future transformations. Although access to mutable state along the same linear chain of Future transformations need not be synchronized, it can be difficult to spot cases where these constraints are violated. The best approach is to use only immutable objects when transforming Futures. When that's not practical, involve only thread-safe mutable objects, as is done in the above example. On Scala.js, by contrast, you need not worry about thread synchronization, because in effect only one thread exists.

    Although BeforeAndAfter provides a minimal-boilerplate way to execute code before and after tests, it isn't designed to enable stackable traits, because the order of execution would be non-obvious. If you want to factor out before and after code that is common to multiple test suites, you should use trait BeforeAndAfterEach instead, as shown later in the next section, composing fixtures by stacking traits.

    Composing fixtures by stacking traits

    In larger projects, teams often end up with several different fixtures that test classes need in different combinations, and possibly initialized (and cleaned up) in different orders. A good way to accomplish this in ScalaTest is to factor the individual fixtures into traits that can be composed using the stackable trait pattern. This can be done, for example, by placing withFixture methods in several traits, each of which call super.withFixture. Here's an example in which the StringBuilderActor and StringBufferActor fixtures used in the previous examples have been factored out into two stackable fixture traits named Builder and Buffer:

    package org.scalatest.examples.asyncfeaturespec.composingwithasyncfixture
    
    import org.scalatest._
    import org.scalatest.SuiteMixin
    import collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringBuilderActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class StringBufferActor {
      private final val buf = ListBuffer.empty[String]
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => buf += value
            case Clear => buf.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[List[String]] =
        Future {
          synchronized { buf.toList }
        }
    }
    
    trait Builder extends AsyncTestSuiteMixin { this: AsyncTestSuite =>
    
      final val builderActor = new StringBuilderActor
    
      abstract override def withFixture(test: NoArgAsyncTest) = {
        builderActor ! Append("ScalaTest is designed to ")
        complete {
          super.withFixture(test) // To be stackable, must call super.withFixture
        } lastly {
          builderActor ! Clear
        }
      }
    }
    
    trait Buffer extends AsyncTestSuiteMixin { this: AsyncTestSuite =>
    
      final val bufferActor = new StringBufferActor
    
      abstract override def withFixture(test: NoArgAsyncTest) = {
        complete {
          super.withFixture(test) // To be stackable, must call super.withFixture
        } lastly {
          bufferActor ! Clear
        }
      }
    }
    
    class ExampleSpec extends AsyncFeatureSpec with Builder with Buffer {
    
      feature("Simplicity") {
        scenario("User needs to read test code written by others") {
          builderActor ! Append("encourage clear code!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is designed to encourage clear code!")
            assert(lst.isEmpty)
            bufferActor ! Append("sweet")
            succeed
          }
        }
    
        scenario("User needs to understand what the tests are doing") {
          builderActor ! Append("be easy to reason about!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is designed to be easy to reason about!")
            assert(lst.isEmpty)
            bufferActor ! Append("awesome")
            succeed
          }
        }
      }
    }
    

    By mixing in both the Builder and Buffer traits, ExampleSpec gets both fixtures, which will be initialized before each test and cleaned up after. The order the traits are mixed together determines the order of execution. In this case, Builder is “super” to Buffer. If you wanted Buffer to be “super” to Builder, you need only switch the order you mix them together, like this:

    class Example2Spec extends AsyncFeatureSpec with Buffer with Builder
    

    If you only need one fixture you mix in only that trait:

    class Example3Spec extends AsyncFeatureSpec with Builder
    

    Another way to create stackable fixture traits is by extending the BeforeAndAfterEach and/or BeforeAndAfterAll traits. BeforeAndAfterEach has 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). Similarly, BeforeAndAfterAll has a beforeAll method that will be run before all tests, and an afterAll method that will be run after all tests. Here's what the previously shown example would look like if it were rewritten to use the BeforeAndAfterEach methods instead of withFixture:

    package org.scalatest.examples.asyncfeaturespec.composingbeforeandaftereach
    
    import org.scalatest._
    import org.scalatest.BeforeAndAfterEach
    import collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringBuilderActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class StringBufferActor {
      private final val buf = ListBuffer.empty[String]
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => buf += value
            case Clear => buf.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[List[String]] =
        Future {
          synchronized { buf.toList }
        }
    }
    
    trait Builder extends BeforeAndAfterEach { this: Suite =>
    
      final val builderActor = new StringBuilderActor
    
      override def beforeEach() {
        builderActor ! Append("ScalaTest is designed to ")
        super.beforeEach() // To be stackable, must call super.beforeEach
      }
    
      override def afterEach() {
        try super.afterEach() // To be stackable, must call super.afterEach
        finally builderActor ! Clear
      }
    }
    
    trait Buffer extends BeforeAndAfterEach { this: Suite =>
    
      final val bufferActor = new StringBufferActor
    
      override def afterEach() {
        try super.afterEach() // To be stackable, must call super.afterEach
        finally bufferActor ! Clear
      }
    }
    
    class ExampleSpec extends AsyncFeatureSpec with Builder with Buffer {
    
      feature("Simplicity") {
    
        scenario("User needs to read test code written by others") {
          builderActor ! Append("encourage clear code!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is designed to encourage clear code!")
            assert(lst.isEmpty)
            bufferActor ! Append("sweet")
            succeed
          }
        }
    
        scenario("User needs to understand what the tests are doing") {
          builderActor ! Append("be easy to reason about!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is designed to be easy to reason about!")
            assert(lst.isEmpty)
            bufferActor ! Append("awesome")
            succeed
          }
        }
      }
    }
    

    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 difference between stacking traits that extend BeforeAndAfterEach versus traits that implement withFixture is that setup and cleanup code happens before and after the test in BeforeAndAfterEach, but at the beginning and end of the test in withFixture. Thus if a withFixture method completes abruptly with an exception, it is considered a failed test. By contrast, if any of the beforeEach or afterEach methods of BeforeAndAfterEach complete abruptly, it is considered an aborted suite, which will result in a SuiteAborted event.

    Shared tests

    Sometimes you may want to run the same test code on different fixture objects. In other words, you may want to write tests that are "shared" by different fixture objects. To accomplish this in an AsyncFeatureSpec, you first place shared tests in behavior functions. These behavior functions will be invoked during the construction phase of any AsyncFeatureSpec that uses them, so that the tests they contain will be registered as tests in that AsyncFeatureSpec. For example, given this StackActor class:

    package org.scalatest.examples.asyncfeaturespec.sharedtests
    
    import scala.collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Stack operations
    case class Push[T](value: T)
    sealed abstract class StackOp
    case object Pop extends StackOp
    case object Peek extends StackOp
    case object Size extends StackOp
    
    // Stack info
    case class StackInfo[T](top: Option[T], size: Int, max: Int) {
      require(size >= 0, "size was less than zero")
      require(max >= size, "max was less than size")
      val isFull: Boolean = size == max
      val isEmpty: Boolean = size == 0
    }
    
    class StackActor[T](Max: Int, name: String) {
    
      private final val buf = new ListBuffer[T]
    
      def !(push: Push[T]): Unit =
        synchronized {
          if (buf.size != Max)
            buf.prepend(push.value)
          else
            throw new IllegalStateException("can't push onto a full stack")
        }
    
      def ?(op: StackOp)(implicit c: ExecutionContext): Future[StackInfo[T]] =
        synchronized {
          op match {
            case Pop =>
              Future {
                if (buf.size != 0)
                  StackInfo(Some(buf.remove(0)), buf.size, Max)
                else
                  throw new IllegalStateException("can't pop an empty stack")
              }
            case Peek =>
              Future {
                if (buf.size != 0)
                  StackInfo(Some(buf(0)), buf.size, Max)
                else
                  throw new IllegalStateException("can't peek an empty stack")
              }
            case Size =>
              Future { StackInfo(None, buf.size, Max) }
          }
        }
    
      override def toString: String = name
    }
    

    You may want to test the stack represented by the StackActor class in different states: empty, full, with one item, with one item less than capacity, etc. You may find you have several tests that make sense any time the stack is non-empty. Thus you'd ideally want to run those same tests for three stack fixture objects: a full stack, a stack with a one item, and a stack with one item less than capacity. With shared tests, you can factor these tests out into a behavior function, into which you pass the stack fixture to use when running the tests. So in your AsyncFeatureSpec for StackActor, you'd invoke the behavior function three times, passing in each of the three stack fixtures so that the shared tests are run for all three fixtures.

    You can define a behavior function that encapsulates these shared tests inside the AsyncFeatureSpec that uses them. If they are shared between different AsyncFeatureSpecs, however, you could also define them in a separate trait that is mixed into each AsyncFeatureSpec that uses them. For example, here the nonEmptyStackActor behavior function (in this case, a behavior method) is defined in a trait along with another method containing shared tests for non-full stacks:

    import org.scalatest.AsyncFeatureSpec
    
    trait AsyncFeatureSpecStackBehaviors { this: AsyncFeatureSpec =>
    
      def nonEmptyStackActor(createNonEmptyStackActor: => StackActor[Int],
            lastItemAdded: Int, name: String): Unit = {
    
        scenario("Size is fired at non-empty stack actor: " + name) {
          val stackActor = createNonEmptyStackActor
          val futureStackInfo = stackActor ? Size
          futureStackInfo map { stackInfo =>
            assert(!stackInfo.isEmpty)
          }
        }
    
        scenario("Peek is fired at non-empty stack actor: " + name) {
          val stackActor = createNonEmptyStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePeek <- stackActor ? Size
              afterPeek <- stackActor ? Peek
            } yield (beforePeek, afterPeek)
          futurePair map { case (beforePeek, afterPeek) =>
            assert(afterPeek.top == Some(lastItemAdded))
            assert(afterPeek.size == beforePeek.size)
          }
        }
    
        scenario("Pop is fired at non-empty stack actor: " + name) {
          val stackActor = createNonEmptyStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePop <- stackActor ? Size
              afterPop <- stackActor ? Pop
            } yield (beforePop, afterPop)
          futurePair map { case (beforePop, afterPop) =>
            assert(afterPop.top == Some(lastItemAdded))
            assert(afterPop.size == beforePop.size - 1)
          }
        }
      }
    
      def nonFullStackActor(createNonFullStackActor: => StackActor[Int], name: String): Unit = {
    
        scenario("Size is fired at non-full stack actor: " + name) {
          val stackActor = createNonFullStackActor
          val futureStackInfo = stackActor ? Size
          futureStackInfo map { stackInfo =>
            assert(!stackInfo.isFull)
          }
        }
    
        scenario("Push is fired at non-full stack actor: " + name) {
          val stackActor = createNonFullStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePush <- stackActor ? Size
              afterPush <- { stackActor ! Push(7); stackActor ? Peek }
            } yield (beforePush, afterPush)
          futurePair map { case (beforePush, afterPush) =>
            assert(afterPush.size == beforePush.size + 1)
            assert(afterPush.top == Some(7))
          }
        }
      }
    }
    

    Given these behavior functions, you could invoke them directly, but AsyncFeatureSpec offers a DSL for the purpose, which looks like this:

    scenariosFor(nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName))
    scenariosFor(nonFullStackActor(almostEmptyStackActor, almostEmptyStackActorName))
    

    Here's an example:

    class StackSpec extends AsyncFeatureSpec with AsyncFeatureSpecStackBehaviors {
    
      val Max = 10
      val LastValuePushed = Max - 1
    
      // Stack fixture creation methods
      val emptyStackActorName = "empty stack actor"
      def emptyStackActor = new StackActor[Int](Max, emptyStackActorName )
    
      val fullStackActorName = "full stack actor"
      def fullStackActor = {
        val stackActor = new StackActor[Int](Max, fullStackActorName )
        for (i <- 0 until Max)
          stackActor ! Push(i)
        stackActor
      }
    
      val almostEmptyStackActorName = "almost empty stack actor"
      def almostEmptyStackActor = {
        val stackActor = new StackActor[Int](Max, almostEmptyStackActorName )
        stackActor ! Push(LastValuePushed)
        stackActor
      }
    
      val almostFullStackActorName = "almost full stack actor"
      def almostFullStackActor = {
        val stackActor = new StackActor[Int](Max, almostFullStackActorName)
        for (i <- 1 to LastValuePushed)
          stackActor ! Push(i)
        stackActor
      }
    
      feature("A Stack is pushed and popped") {
    
        scenario("Size is fired at empty stack actor") {
          val stackActor = emptyStackActor
          val futureStackInfo = stackActor ? Size
          futureStackInfo map { stackInfo =>
            assert(stackInfo.isEmpty)
          }
        }
    
        scenario("Peek is fired at empty stack actor") {
          recoverToSucceededIf[IllegalStateException] {
            emptyStackActor ? Peek
          }
        }
    
        scenario("Pop is fired at empty stack actor") {
          recoverToSucceededIf[IllegalStateException] {
            emptyStackActor ? Pop
          }
        }
    
        scenariosFor(nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName))
        scenariosFor(nonFullStackActor(almostEmptyStackActor, almostEmptyStackActorName))
    
        scenariosFor(nonEmptyStackActor(almostFullStackActor, LastValuePushed, almostFullStackActorName))
        scenariosFor(nonFullStackActor(almostFullStackActor, almostFullStackActorName))
    
        scenario("full is invoked on a full stack") {
          val stackActor = fullStackActor
          val futureStackInfo = stackActor ? Size
          futureStackInfo map { stackInfo =>
            assert(stackInfo.isFull)
          }
        }
    
        scenariosFor(nonEmptyStackActor(fullStackActor, LastValuePushed, fullStackActorName))
    
        scenario("push is invoked on a full stack") {
          val stackActor = fullStackActor
          assertThrows[IllegalStateException] {
            stackActor ! Push(10)
          }
        }
      }
    }
    

    If you load these classes into the Scala interpreter (with scalatest's JAR file on the class path), and execute it, you'll see:

    scala> org.scalatest.run(new StackSpec)
    StackSpec:
    Feature: A Stack actor
    - Scenario: Size is fired at empty stack actor
    - Scenario: Peek is fired at empty stack actor
    - Scenario: Pop is fired at empty stack actor
    - Scenario: Size is fired at non-empty stack actor: almost empty stack actor
    - Scenario: Peek is fired at non-empty stack actor: almost empty stack actor
    - Scenario: Pop is fired at non-empty stack actor: almost empty stack actor
    - Scenario: Size is fired at non-full stack actor: almost empty stack actor
    - Scenario: Push is fired at non-full stack actor: almost empty stack actor
    - Scenario: Size is fired at non-empty stack actor: almost full stack actor
    - Scenario: Peek is fired at non-empty stack actor: almost full stack actor
    - Scenario: Pop is fired at non-empty stack actor: almost full stack actor
    - Scenario: Size is fired at non-full stack actor: almost full stack actor
    - Scenario: Push is fired at non-full stack actor: almost full stack actor
    - Scenario: Size is fired at full stack actor
    - Scenario: Size is fired at non-empty stack actor: full stack actor
    - Scenario: Peek is fired at non-empty stack actor: full stack actor
    - Scenario: Pop is fired at non-empty stack actor: full stack actor
    - Scenario: Push is fired at full stack actor
    
    

    One thing to keep in mind when using shared tests is that in ScalaTest, each test in a suite must have a unique name. If you register the same tests repeatedly in the same suite, one problem you may encounter is an exception at runtime complaining that multiple tests are being registered with the same test name. Although in an AsyncFeatureSpec, the feature clause is a nesting construct analogous to AsyncFunSpec's describe clause, you many sometimes need to do a bit of extra work to ensure that the test names are unique. If a duplicate test name problem shows up in an AsyncFeatureSpec, you'll need to pass in a prefix or suffix string to add to each test name. You can call toString on the shared fixture object, or pass this string the same way you pass any other data needed by the shared tests. This is the approach taken by the previous AsyncFeatureSpecStackBehaviors example.

    Given this AsyncFeatureSpecStackBehaviors trait, calling it with the almostEmptyStackActor fixture, like this:

    scenariosFor(nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName))
    

    yields test names:

    • Size is fired at non-empty stack actor: almost empty stack actor
    • Peek is fired at non-empty stack actor: almost empty stack actor
    • Pop is fired at non-empty stack actor: almost empty stack actor

    Whereas calling it with the almostFullStackActor fixture, like this:

    scenariosFor(nonEmptyStack(almostFullStackActor, lastValuePushed, almostFullStackActorName))
    

    yields different test names:

    • Size is fired at non-empty stack actor: almost full stack actor
    • Peek is fired at non-empty stack actor: almost full stack actor
    • Pop is fired at non-empty stack actor: almost full stack actor
  8. trait AsyncFeatureSpecLike extends AsyncTestSuite with AsyncTestRegistration with Informing with Notifying with Alerting with Documenting

    Permalink

    Implementation trait for class AsyncFeatureSpec, which represents a suite of tests in which each test represents one scenario of a feature.

    Implementation trait for class AsyncFeatureSpec, which represents a suite of tests in which each test represents one scenario of a feature.

    AsyncFeatureSpec 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 AsyncFeatureSpec into some other class, you can use this trait instead, because class AsyncFeatureSpec does nothing more than extend this trait and add a nice toString implementation.

    See the documentation of the class for a detailed overview of AsyncFeatureSpec.

    Annotations
    @JSExportDescendentClasses( true ) @Finders()
  9. abstract class AsyncFlatSpec extends AsyncFlatSpecLike

    Permalink

    Enables testing of asynchronous code without blocking, using a style consistent with traditional FlatSpec tests.

    Enables testing of asynchronous code without blocking, using a style consistent with traditional FlatSpec tests.

    Recommended Usage: AsyncFlatSpec is intended to enable users of FlatSpec to write non-blocking asynchronous tests that are consistent with their traditional FlatSpec tests. Note: AsyncFlatSpec is intended for use in special situations where non-blocking asynchronous testing is needed, with class FlatSpec used for general needs.

    Given a Future returned by the code you are testing, you need not block until the Future completes before performing assertions against its value. You can instead map those assertions onto the Future and return the resulting Future[Assertion] to ScalaTest. The test will complete asynchronously, when the Future[Assertion] completes.

    Trait AsyncFlatSpec is so named because your specification text and tests line up flat against the left-side indentation level, with no nesting needed. Here's an example AsyncFlatSpec:

    package org.scalatest.examples.asyncflatspec
    
    import org.scalatest.AsyncFlatSpec
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFlatSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      behavior of "addSoon"
    
      it should "eventually compute a sum of passed Ints" in {
        val futureSum: Future[Int] = addSoon(1, 2)
        // You can map assertions onto a Future, then return
        // the resulting Future[Assertion] to ScalaTest:
        futureSum map { sum => assert(sum == 3) }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" should "immediately compute a sum of passed Ints" in {
        val sum: Int = addNow(1, 2)
        // You can also write synchronous tests. The body
        // must have result type Assertion:
        assert(sum == 3)
      }
    }
    

    The initial test in this example demonstrates the use of an explicit behavior of clause, which establishes addSoon as the subject. The second test demonstrates the alternate syntax of replacing the first it with the subject string, in this case, "addNow". As with traditional FlatSpecs, you can use must or can as well as should. For example, instead of it should "eventually..., you could write it must "eventually... or it can "eventually.... You can also write they instead of it. See the documentation for FlatSpec for more detail.

    Running the above AddSpec in the Scala interpreter would yield:

    addSoon
    - should eventually compute a sum of passed Ints
    - should immediately compute a sum of passed Ints
    

    Starting with version 3.0.0, ScalaTest assertions and matchers have result type Assertion. The result type of the first test in the example above, therefore, is Future[Assertion]. For clarity, here's the relevant code in a REPL session:

    scala> import org.scalatest._
    import org.scalatest._
    
    scala> import Assertions._
    import Assertions._
    
    scala> import scala.concurrent.Future
    import scala.concurrent.Future
    
    scala> import scala.concurrent.ExecutionContext
    import scala.concurrent.ExecutionContext
    
    scala> implicit val executionContext = ExecutionContext.Implicits.global
    executionContext: scala.concurrent.ExecutionContextExecutor = [email protected]
    
    scala> def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    addSoon: (addends: Int*)scala.concurrent.Future[Int]
    
    scala> val futureSum: Future[Int] = addSoon(1, 2)
    futureSum: scala.concurrent.Future[Int] = [email protected]
    
    scala> futureSum map { sum => assert(sum == 3) }
    res0: scala.concurrent.Future[org.scalatest.Assertion] = [email protected]
    

    The second test has result type Assertion:

    scala> def addNow(addends: Int*): Int = addends.sum
    addNow: (addends: Int*)Int
    
    scala> val sum: Int = addNow(1, 2)
    sum: Int = 3
    
    scala> assert(sum == 3)
    res1: org.scalatest.Assertion = Succeeded
    

    When AddSpec is constructed, the second test will be implicitly converted to Future[Assertion] and registered. The implicit conversion is from Assertion to Future[Assertion], so you must end synchronous tests in some ScalaTest assertion or matcher expression. If a test would not otherwise end in type Assertion, you can place succeed at the end of the test. succeed, a field in trait Assertions, returns the Succeeded singleton:

    scala> succeed
    res2: org.scalatest.Assertion = Succeeded
    

    Thus placing succeed at the end of a test body will satisfy the type checker:

      "addNow" should "immediately compute a sum of passed Ints" in {
        val sum: Int = addNow(1, 2)
        assert(sum == 3)
        println("hi") // println has result type Unit
        succeed       // succeed has result type Assertion
      }
    

    An AsyncFlatSpec's lifecycle has two phases: the registration phase and the ready phase. It starts in registration phase and enters ready phase the first time run is called on it. It then remains in ready phase for the remainder of its lifetime.

    Tests can only be registered with the it method while the AsyncFlatSpec is in its registration phase. Any attempt to register a test after the AsyncFlatSpec has entered its ready phase, i.e., after run has been invoked on the AsyncFlatSpec, will be met with a thrown TestRegistrationClosedException. The recommended style of using AsyncFlatSpec is to register tests during object construction as is done in all the examples shown here. If you keep to the recommended style, you should never see a TestRegistrationClosedException.

    Asynchronous execution model

    AsyncFlatSpec extends AsyncTestSuite, which provides an implicit scala.concurrent.ExecutionContext named executionContext. This execution context is used by AsyncFlatSpec to transform the Future[Assertion]s returned by each test into the FutureOutcome returned by the test function passed to withFixture. This ExecutionContext is also intended to be used in the tests, including when you map assertions onto futures.

    On both the JVM and Scala.js, the default execution context provided by ScalaTest's asynchronous testing styles confines execution to a single thread per test. On JavaScript, where single-threaded execution is the only possibility, the default execution context is scala.scalajs.concurrent.JSExecutionContext.Implicits.queue. On the JVM, the default execution context is a serial execution context provided by ScalaTest itself.

    When ScalaTest's serial execution context is called upon to execute a task, that task is recorded in a queue for later execution. For example, one task that will be placed in this queue is the task that transforms the Future[Assertion] returned by an asynchronous test body to the FutureOutcome returned from the test function. Other tasks that will be queued are any transformations of, or callbacks registered on, Futures that occur in your test body, including any assertions you map onto Futures. Once the test body returns, the thread that executed the test body will execute the tasks in that queue one after another, in the order they were enqueued.

    ScalaTest provides its serial execution context as the default on the JVM for three reasons. First, most often running both tests and suites in parallel does not give a significant performance boost compared to just running suites in parallel. Thus parallel execution of Future transformations within individual tests is not generally needed for performance reasons.

    Second, if multiple threads are operating in the same suite concurrently, you'll need to make sure access to any mutable fixture objects by multiple threads is synchronized. Although access to mutable state along the same linear chain of Future transformations need not be synchronized, this does not hold true for callbacks, and in general it is easy to make a mistake. Simply put: synchronizing access to shared mutable state is difficult and error prone. Because ScalaTest's default execution context on the JVM confines execution of Future transformations and call backs to a single thread, you need not (by default) worry about synchronizing access to mutable state in your asynchronous-style tests.

    Third, asynchronous-style tests need not be complete when the test body returns, because the test body returns a Future[Assertion]. This Future[Assertion] will often represent a test that has not yet completed. As a result, when using a more traditional execution context backed by a thread-pool, you could potentially start many more tests executing concurrently than there are threads in the thread pool. The more concurrently execute tests you have competing for threads from the same limited thread pool, the more likely it will be that tests will intermitently fail due to timeouts.

    Using ScalaTest's serial execution context on the JVM will ensure the same thread that produced the Future[Assertion] returned from a test body is also used to execute any tasks given to the execution context while executing the test body—and that thread will not be allowed to do anything else until the test completes. If the serial execution context's task queue ever becomes empty while the Future[Assertion] returned by that test's body has not yet completed, the thread will block until another task for that test is enqueued. Although it may seem counter-intuitive, this blocking behavior means the total number of tests allowed to run concurrently will be limited to the total number of threads executing suites. This fact means you can tune the thread pool such that maximum performance is reached while avoiding (or at least, reducing the likelihood of) tests that fail due to timeouts because of thread competition.

    This thread confinement strategy does mean, however, that when you are using the default execution context on the JVM, you must be sure to never block in the test body waiting for a task to be completed by the execution context. If you block, your test will never complete. This kind of problem will be obvious, because the test will consistently hang every time you run it. (If a test is hanging, and you're not sure which one it is, enable slowpoke notifications.) If you really do want to block in your tests, you may wish to just use a traditional FlatSpec with ScalaFutures instead. Alternatively, you could override the executionContext and use a traditional ExecutionContext backed by a thread pool. This will enable you to block in an asynchronous-style test on the JVM, but you'll need to worry about synchronizing access to shared mutable state.

    To use a different execution context, just override executionContext. For example, if you prefer to use the runNow execution context on Scala.js instead of the default queue, you would write:

    // on Scala.js
    implicit override def executionContext =
        scala.scalajs.concurrent.JSExecutionContext.Implicits.runNow
    

    If you prefer on the JVM to use the global execution context, which is backed by a thread pool, instead of ScalaTest's default serial execution contex, which confines execution to a single thread, you would write:

    // on the JVM (and also compiles on Scala.js, giving
    // you the queue execution context)
    implicit override def executionContext =
        scala.concurrent.ExecutionContext.Implicits.global
    

    Serial and parallel test execution

    By default (unless you mix in ParallelTestExecution), tests in an AsyncFlatSpec will be executed one after another, i.e., serially. This is true whether those tests return Assertion or Future[Assertion], no matter what threads are involved. This default behavior allows you to re-use a shared fixture, such as an external database that needs to be cleaned after each test, in multiple tests in async-style suites. This is implemented by registering each test, other than the first test, to run as a continuation after the previous test completes.

    If you want the tests of an AsyncFlatSpec to be executed in parallel, you must mix in ParallelTestExecution and enable parallel execution of tests in your build. You enable parallel execution in Runner with the -P command line flag. In the ScalaTest Maven Plugin, set parallel to true. In sbt, parallel execution is the default, but to be explicit you can write:

    parallelExecution in Test := true // the default in sbt
    

    On the JVM, if both ParallelTestExecution is mixed in and parallel execution is enabled in the build, tests in an async-style suite will be started in parallel, using threads from the Distributor, and allowed to complete in parallel, using threads from the executionContext. If you are using ScalaTest's serial execution context, the JVM default, asynchronous tests will run in parallel very much like traditional (such as FlatSpec) tests run in parallel: 1) Because ParallelTestExecution extends OneInstancePerTest, each test will run in its own instance of the test class, you need not worry about synchronizing access to mutable instance state shared by different tests in the same suite. 2) Because the serial execution context will confine the execution of each test to the single thread that executes the test body, you need not worry about synchronizing access to shared mutable state accessed by transformations and callbacks of Futures inside the test.

    If ParallelTestExecution is mixed in but parallel execution of suites is not enabled, asynchronous tests on the JVM will be started sequentially, by the single thread that invoked run, but without waiting for one test to complete before the next test is started. As a result, asynchronous tests will be allowed to complete in parallel, using threads from the executionContext. If you are using the serial execution context, however, you'll see the same behavior you see when parallel execution is disabled and a traditional suite that mixes in ParallelTestExecution is executed: the tests will run sequentially. If you use an execution context backed by a thread-pool, such as global, however, even though tests will be started sequentially by one thread, they will be allowed to run concurrently using threads from the execution context's thread pool.

    The latter behavior is essentially what you'll see on Scala.js when you execute a suite that mixes in ParallelTestExecution. Because only one thread exists when running under JavaScript, you can't "enable parallel execution of suites." However, it may still be useful to run tests in parallel on Scala.js, because tests can invoke API calls that are truly asynchronous by calling into external APIs that take advantage of non-JavaScript threads. Thus on Scala.js, ParallelTestExecution allows asynchronous tests to run in parallel, even though they must be started sequentially. This may give you better performance when you are using API calls in your Scala.js tests that are truly asynchronous.

    Futures and expected exceptions

    If you need to test for expected exceptions in the context of futures, you can use the recoverToSucceededIf and recoverToExceptionIf methods of trait RecoverMethods. Because this trait is mixed into supertrait AsyncTestSuite, both of these methods are available by default in an AsyncFlatSpec.

    If you just want to ensure that a future fails with a particular exception type, and do not need to inspect the exception further, use recoverToSucceededIf:

    recoverToSucceededIf[IllegalStateException] { // Result type: Future[Assertion]
      emptyStackActor ? Peek
    }
    

    The recoverToSucceededIf method performs a job similar to assertThrows, except in the context of a future. It transforms a Future of any type into a Future[Assertion] that succeeds only if the original future fails with the specified exception. Here's an example in the REPL:

    scala> import org.scalatest.RecoverMethods._
    import org.scalatest.RecoverMethods._
    
    scala> import scala.concurrent.Future
    import scala.concurrent.Future
    
    scala> import scala.concurrent.ExecutionContext.Implicits.global
    import scala.concurrent.ExecutionContext.Implicits.global
    
    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { throw new IllegalStateException }
         | }
    res0: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res0.value
    res1: Option[scala.util.Try[org.scalatest.Assertion]] = Some(Success(Succeeded))
    

    Otherwise it fails with an error message similar to those given by assertThrows:

    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { throw new RuntimeException }
         | }
    res2: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res2.value
    res3: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: Expected exception
          java.lang.IllegalStateException to be thrown, but java.lang.RuntimeException
          was thrown))
    
    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { 42 }
         | }
    res4: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res4.value
    res5: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: Expected exception
          java.lang.IllegalStateException to be thrown, but no exception was thrown))
    

    The recoverToExceptionIf method differs from the recoverToSucceededIf in its behavior when the assertion succeeds: recoverToSucceededIf yields a Future[Assertion], whereas recoverToExceptionIf yields a Future[T], where T is the expected exception type.

    recoverToExceptionIf[IllegalStateException] { // Result type: Future[IllegalStateException]
      emptyStackActor ? Peek
    }
    

    In other words, recoverToExpectionIf is to intercept as recovertToSucceededIf is to assertThrows. The first one allows you to perform further assertions on the expected exception. The second one gives you a result type that will satisfy the type checker at the end of the test body. Here's an example showing recoverToExceptionIf in the REPL:

    scala> val futureEx =
         |   recoverToExceptionIf[IllegalStateException] {
         |     Future { throw new IllegalStateException("hello") }
         |   }
    futureEx: scala.concurrent.Future[IllegalStateException] = ...
    
    scala> futureEx.value
    res6: Option[scala.util.Try[IllegalStateException]] =
        Some(Success(java.lang.IllegalStateException: hello))
    
    scala> futureEx map { ex => assert(ex.getMessage == "world") }
    res7: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res7.value
    res8: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: "[hello]" did not equal "[world]"))
    

    Ignored tests

    To support the common use case of temporarily disabling a test, with the good intention of resurrecting the test at a later time, AsyncFlatSpec provides two ways to ignore a test, both demonstrated in the following example:

    package org.scalatest.examples.asyncflatspec.ignore
    
    import org.scalatest.AsyncFlatSpec
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFlatSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      behavior of "addSoon"
    
      ignore should "eventually compute a sum of passed Ints" in {
        val futureSum: Future[Int] = addSoon(1, 2)
        // You can map assertions onto a Future, then return
        // the resulting Future[Assertion] to ScalaTest:
        futureSum map { sum => assert(sum == 3) }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" should "immediately compute a sum of passed Ints" ignore {
        val sum: Int = addNow(1, 2)
        // You can also write synchronous tests. The body
        // must have result type Assertion:
        assert(sum == 3)
      }
    }
    

    In the first test, ignore is used instead of it. In the second test, which uses the shorthand notation, no it exists to change into ignore. To ignore such tests, you must instead change in to ignore, as shown in the above example. If you run this version of AddSpec with:

    scala> org.scalatest.run(new AddSpec)
    

    It will report both tests as ignored:

    AddSpec:
    addSoon
    - should eventually compute a sum of passed Ints !!! IGNORED !!!
    addNow
    - should immediately compute a sum of passed Ints !!! IGNORED !!!
    

    If you wish to temporarily ignore an entire suite of tests, you can (on the JVM, not Scala.js) annotate the test class with @Ignore, like this:

    package org.scalatest.examples.asyncflatspec.ignoreall
    
    import org.scalatest.AsyncFlatSpec
    import scala.concurrent.Future
    import org.scalatest.Ignore
    
    @Ignore
    class AddSpec extends AsyncFlatSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "addSoon" should "eventually compute a sum of passed Ints" in {
        val futureSum: Future[Int] = addSoon(1, 2)
        // You can map assertions onto a Future, then return
        // the resulting Future[Assertion] to ScalaTest:
        futureSum map { sum => assert(sum == 3) }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" should "immediately compute a sum of passed Ints" in {
        val sum: Int = addNow(1, 2)
        // You can also write synchronous tests. The body
        // must have result type Assertion:
        assert(sum == 3)
      }
    }
    

    When you mark a test class with a tag annotation, ScalaTest will mark each test defined in that class with that tag. Thus, marking the AddSpec in the above example with the @Ignore tag annotation means that both tests in the class will be ignored. If you run the above AddSpec in the Scala interpreter, you'll see:

    AddSpec:
    addSoon
    - should eventually compute a sum of passed Ints !!! IGNORED !!!
    addNow
    - should immediately compute a sum of passed Ints !!! IGNORED !!!
    

    Note that marking a test class as ignored won't prevent it from being discovered by ScalaTest. Ignored classes will be discovered and run, and all their tests will be reported as ignored. This is intended to keep the ignored class visible, to encourage the developers to eventually fix and “un-ignore” it. If you want to prevent a class from being discovered at all (on the JVM, not Scala.js), use the DoNotDiscover annotation instead.

    If you want to ignore all tests of a suite on Scala.js, where annotations can't be inspected at runtime, you'll need to change it to ignore at each test site. To make a suite non-discoverable on Scala.js, ensure it does not declare a public no-arg constructor. You can either declare a public constructor that takes one or more arguments, or make the no-arg constructor non-public. Because this technique will also make the suite non-discoverable on the JVM, it is a good approach for suites you want to run (but not be discoverable) on both Scala.js and the JVM.

    Informers

    One of the parameters to AsyncFlatSpec's run method is a Reporter, which will collect and report information about the running suite of tests. Information about suites and tests that were run, whether tests succeeded or failed, and tests that were ignored will be passed to the Reporter as the suite runs. Most often the reporting done by default by AsyncFlatSpec's methods will be sufficient, but occasionally you may wish to provide custom information to the Reporter from a test. For this purpose, an Informer that will forward information to the current Reporter is provided via the info parameterless method. You can pass the extra information to the Informer via its apply method. The Informer will then pass the information to the Reporter via an InfoProvided event.

    One use case for the Informer is to pass more information about a specification to the reporter. For example, the GivenWhenThen trait provides methods that use the implicit info provided by AsyncFlatSpec to pass such information to the reporter. Here's an example:

    package org.scalatest.examples.asyncflatspec.info
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends AsyncFlatSpec with GivenWhenThen {
    
      "A mutable Set" should "allow an element to be added" in {
        Given("an empty mutable Set")
        val set = mutable.Set.empty[String]
    
        When("an element is added")
        set += "clarity"
    
        Then("the Set should have size 1")
        assert(set.size === 1)
    
        And("the Set should contain the added element")
        assert(set.contains("clarity"))
    
        info("That's all folks!")
        succeed
      }
    }
    

    If you run this AsyncFlatSpec from the interpreter, you will see the following output:

    scala> org.scalatest.run(new SetSpec)
    SetSpec:
    A mutable Set
    - should allow an element to be added
      + Given an empty mutable Set
      + When an element is added
      + Then the Set should have size 1
      + And the Set should contain the added element
      + That's all folks! 
    

    Documenters

    AsyncFlatSpec also provides a markup method that returns a Documenter, which allows you to send to the Reporter text formatted in Markdown syntax. You can pass the extra information to the Documenter via its apply method. The Documenter will then pass the information to the Reporter via an MarkupProvided event.

    Here's an example AsyncFlatSpec that uses markup:

    package org.scalatest.examples.asyncflatspec.markup
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends AsyncFlatSpec with GivenWhenThen {
    
      markup { """
    
    Mutable Set
    -----------
    
    A set is a collection that contains no duplicate elements.
    
    To implement a concrete mutable set, you need to provide implementations
    of the following methods:
    
        def contains(elem: A): Boolean
        def iterator: Iterator[A]
        def += (elem: A): this.type
        def -= (elem: A): this.type
    
    If you wish that methods like `take`,
    `drop`, `filter` return the same kind of set,
    you should also override:
    
        def empty: This
    
    It is also good idea to override methods `foreach` and
    `size` for efficiency.
    
      """ }
    
      "A mutable Set" should "allow an element to be added" in {
        Given("an empty mutable Set")
        val set = mutable.Set.empty[String]
    
        When("an element is added")
        set += "clarity"
    
        Then("the Set should have size 1")
        assert(set.size === 1)
    
        And("the Set should contain the added element")
        assert(set.contains("clarity"))
    
        markup("This test finished with a **bold** statement!")
        succeed
      }
    }
    

    Although all of ScalaTest's built-in reporters will display the markup text in some form, the HTML reporter will format the markup information into HTML. Thus, the main purpose of markup is to add nicely formatted text to HTML reports. Here's what the above SetSpec would look like in the HTML reporter:

    Notifiers and alerters

    ScalaTest records text passed to info and markup during tests, and sends the recorded text in the recordedEvents field of test completion events like TestSucceeded and TestFailed. This allows string reporters (like the standard out reporter) to show info and markup text after the test name in a color determined by the outcome of the test. For example, if the test fails, string reporters will show the info and markup text in red. If a test succeeds, string reporters will show the info and markup text in green. While this approach helps the readability of reports, it means that you can't use info to get status updates from long running tests.

    To get immediate (i.e., non-recorded) notifications from tests, you can use note (a Notifier) and alert (an Alerter). Here's an example showing the differences:

    package org.scalatest.examples.asyncflatspec.note
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends AsyncFlatSpec {
    
      "A mutable Set" should "allow an element to be added" in {
    
        info("info is recorded")
        markup("markup is *also* recorded")
        note("notes are sent immediately")
        alert("alerts are also sent immediately")
    
        val set = mutable.Set.empty[String]
        set += "clarity"
        assert(set.size === 1)
        assert(set.contains("clarity"))
      }
    }
    

    Because note and alert information is sent immediately, it will appear before the test name in string reporters, and its color will be unrelated to the ultimate outcome of the test: note text will always appear in green, alert text will always appear in yellow. Here's an example:

    scala> org.scalatest.run(new SetSpec)
    SetSpec:
    A mutable Set
      + notes are sent immediately
      + alerts are also sent immediately
    - should allow an element to be added
      + info is recorded
      + markup is *also* recorded
    

    Another example is slowpoke notifications. If you find a test is taking a long time to complete, but you're not sure which test, you can enable slowpoke notifications. ScalaTest will use an Alerter to fire an event whenever a test has been running longer than a specified amount of time.

    In summary, use info and markup for text that should form part of the specification output. Use note and alert to send status notifications. (Because the HTML reporter is intended to produce a readable, printable specification, info and markup text will appear in the HTML report, but note and alert text will not.)

    Pending tests

    A pending test is one that has been given a name but is not yet implemented. The purpose of pending tests is to facilitate a style of testing in which documentation of behavior is sketched out before tests are written to verify that behavior (and often, before the behavior of the system being tested is itself implemented). Such sketches form a kind of specification of what tests and functionality to implement later.

    To support this style of testing, a test can be given a name that specifies one bit of behavior required by the system being tested. At the end of the test, it can call method pending, which will cause it to complete abruptly with TestPendingException.

    Because tests in ScalaTest can be designated as pending with TestPendingException, both the test name and any information sent to the reporter when running the test can appear in the report of a test run. (In other words, the code of a pending test is executed just like any other test.) However, because the test completes abruptly with TestPendingException, the test will be reported as pending, to indicate the actual test, and possibly the functionality, has not yet been implemented. Here's an example:

    package org.scalatest.examples.asyncflatspec.pending
    
    import org.scalatest.AsyncFlatSpec
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFlatSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "addSoon" should "eventually compute a sum of passed Ints" in (pending)
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" should "immediately compute a sum of passed Ints" in {
        val sum: Int = addNow(1, 2)
        // You can also write synchronous tests. The body
        // must have result type Assertion:
        assert(sum == 3)
      }
    }
    

    (Note: "(pending)" is the body of the test. Thus the test contains just one statement, an invocation of the pending method, which throws TestPendingException.) If you run this version of AddSpec with:

    scala> org.scalatest.run(new AddSpec)
    

    It will run both tests, but report that first test is pending. You'll see:

    AddSpec:
    addSoon
    - should eventually compute a sum of passed Ints (pending)
    addNow
    - should immediately compute a sum of passed Ints
    

    One difference between an ignored test and a pending one is that an ignored test is intended to be used during significant refactorings of the code under test, when tests break and you don't want to spend the time to fix all of them immediately. You can mark some of those broken tests as ignored temporarily, so that you can focus the red bar on just failing tests you actually want to fix immediately. Later you can go back and fix the ignored tests. In other words, by ignoring some failing tests temporarily, you can more easily notice failed tests that you actually want to fix. By contrast, a pending test is intended to be used before a test and/or the code under test is written. Pending indicates you've decided to write a test for a bit of behavior, but either you haven't written the test yet, or have only written part of it, or perhaps you've written the test but don't want to implement the behavior it tests until after you've implemented a different bit of behavior you realized you need first. Thus ignored tests are designed to facilitate refactoring of existing code whereas pending tests are designed to facilitate the creation of new code.

    One other difference between ignored and pending tests is that ignored tests are implemented as a test tag that is excluded by default. Thus an ignored test is never executed. By contrast, a pending test is implemented as a test that throws TestPendingException (which is what calling the pending method does). Thus the body of pending tests are executed up until they throw TestPendingException.

    Tagging tests

    An AsyncFlatSpec's tests may be classified into groups by tagging them with string names. As with any suite, when executing an AsyncFlatSpec, groups of tests can optionally be included and/or excluded. To tag an AsyncFlatSpec's tests, you pass objects that extend class org.scalatest.Tag to methods that register tests. Class Tag takes one parameter, a string name. If you have created tag annotation interfaces as described in the Tag documentation, then you will probably want to use tag names on your test functions that match. To do so, simply pass the fully qualified names of the tag interfaces to the Tag constructor. For example, if you've defined a tag annotation interface with fully qualified name, com.mycompany.tags.DbTest, then you could create a matching tag for AsyncFlatSpecs like this:

    package org.scalatest.examples.asyncflatspec.tagging
    
    import org.scalatest.Tag
    
    object DbTest extends Tag("com.mycompany.tags.DbTest")
    

    Given these definitions, you could place AsyncFlatSpec tests into groups with tags like this:

    import org.scalatest.AsyncFlatSpec
    import org.scalatest.tagobjects.Slow
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFlatSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "addSoon" should "eventually compute a sum of passed Ints" taggedAs(Slow) in {
        val futureSum: Future[Int] = addSoon(1, 2)
        // You can map assertions onto a Future, then return
        // the resulting Future[Assertion] to ScalaTest:
        futureSum map { sum => assert(sum == 3) }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" should "immediately compute a sum of passed Ints" taggedAs(Slow, DbTest) in {
        val sum: Int = addNow(1, 2)
        // You can also write synchronous tests. The body
        // must have result type Assertion:
        assert(sum == 3)
      }
    }
    

    This code marks both tests with the org.scalatest.tags.Slow tag, and the second test with the com.mycompany.tags.DbTest tag.

    The run method takes a Filter, whose constructor takes an optional Set[String] called tagsToInclude and a Set[String] called tagsToExclude. If tagsToInclude is None, all tests will be run except those those belonging to tags listed in the tagsToExclude Set. If tagsToInclude is defined, only tests belonging to tags mentioned in the tagsToInclude set, and not mentioned in tagsToExclude, will be run.

    It is recommended, though not required, that you create a corresponding tag annotation when you create a Tag object. A tag annotation (on the JVM, not Scala.js) allows you to tag all the tests of an AsyncFlatSpec in one stroke by annotating the class. For more information and examples, see the documentation for class Tag. On Scala.js, to tag all tests of a suite, you'll need to tag each test individually at the test site.

    Shared fixtures

    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.

    ScalaTest recommends three techniques to eliminate such code duplication in async styles:

    • Refactor using Scala
    • Override withFixture
    • Mix in a before-and-after trait

    Each technique is geared towards helping you reduce code duplication without introducing instance vars, shared mutable objects, or other dependencies between tests. Eliminating shared mutable state across tests will make your test code easier to reason about and eliminate the need to synchronize access to shared mutable state on the JVM.

    The following sections describe these techniques, including explaining the recommended usage for each. But first, here's a table summarizing the options:

    Refactor using Scala when different tests need different fixtures.
    get-fixture methods The extract method refactor helps you create a fresh instances of mutable fixture objects in each test that needs them, but doesn't help you clean them up when you're done.
    loan-fixture methods Factor out dupicate code with the loan pattern when different tests need different fixtures that must be cleaned up afterwards.
    Override withFixture when most or all tests need the same fixture.
    withFixture(NoArgAsyncTest) The recommended default approach when most or all tests need the same fixture treatment. This general technique allows you, for example, to perform side effects at the beginning and end of all or most tests, transform the outcome of tests, retry tests, make decisions based on test names, tags, or other test data. Use this technique unless:
    Different tests need different fixtures (refactor using Scala instead)
    An exception in fixture code should abort the suite, not fail the test (use a before-and-after trait instead)
    You have objects to pass into tests (override withFixture(OneArgAsyncTest) instead)
    withFixture(OneArgAsyncTest) Use when you want to pass the same fixture object or objects as a parameter into all or most tests.
    Mix in a before-and-after trait when you want an aborted suite, not a failed test, if the fixture code fails.
    BeforeAndAfter Use this boilerplate-buster when you need to perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.
    BeforeAndAfterEach Use when you want to stack traits that perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.

    Calling get-fixture methods

    If you need to create the same mutable fixture objects in multiple tests, and don't need to clean them up after using them, the simplest approach is to write one or more get-fixture methods. A get-fixture method returns a new instance of a needed fixture object (or a holder object containing multiple fixture objects) each time it is called. You can call a get-fixture method at the beginning of each test that needs the fixture, storing the returned object or objects in local variables. Here's an example:

    package org.scalatest.examples.asyncflatspec.getfixture
    
    import org.scalatest.AsyncFlatSpec
    import scala.concurrent.Future
    
    class ExampleSpec extends AsyncFlatSpec {
    
      def fixture: Future[String] = Future { "ScalaTest is " }
    
      "Testing" should "be easy" in {
        val future = fixture
        val result = future map { s => s + "easy!" }
        result map { s =>
          assert(s == "ScalaTest is easy!")
        }
      }
    
      it should "be fun" in {
        val future = fixture
        val result = future map { s => s + "fun!" }
        result map { s =>
          assert(s == "ScalaTest is fun!")
        }
      }
    }
    

    If you need to configure fixture objects differently in different tests, you can pass configuration into the get-fixture method. For example, you could pass in an initial value for a fixture object as a parameter to the get-fixture method.

    Overriding withFixture(NoArgAsyncTest)

    Although the get-fixture method approach takes care of setting up a fixture at the beginning of each test, it doesn't address the problem of cleaning up a fixture at the end of the test. If you just need to perform a side-effect at the beginning or end of a test, and don't need to actually pass any fixture objects into the test, you can override withFixture(NoArgAsyncTest), a method defined in trait AsyncTestSuite, a supertrait of AsyncFlatSpec.

    Trait AsyncFlatSpec's runTest method passes a no-arg async test function to withFixture(NoArgAsyncTest). It is withFixture's responsibility to invoke that test function. The default implementation of withFixture simply invokes the function and returns the result, like this:

    // Default implementation in trait AsyncTestSuite
    protected def withFixture(test: NoArgAsyncTest): FutureOutcome = {
      test()
    }
    

    You can, therefore, override withFixture to perform setup before invoking the test function, and/or perform cleanup after the test completes. The recommended way to ensure cleanup is performed after a test completes is to use the complete-lastly syntax, defined in supertrait CompleteLastly. The complete-lastly syntax will ensure that cleanup will occur whether future-producing code completes abruptly by throwing an exception, or returns normally yielding a future. In the latter case, complete-lastly will register the cleanup code to execute asynchronously when the future completes.

    The withFixture method is designed to be stacked, and to enable this, you should always call the super implementation of withFixture, 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)”, like this:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      complete {
        super.withFixture(test) // Invoke the test function
      } lastly {
        // Perform cleanup here
      }
    }
    

    If you have no cleanup to perform, you can write withFixture like this instead:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      super.withFixture(test) // Invoke the test function
    }
    

    If you want to perform an action only for certain outcomes, you'll need to register code performing that action as a callback on the Future using one of Future's registration methods: onComplete, onSuccess, or onFailure. Note that if a test fails, that will be treated as a scala.util.Success(org.scalatest.Failed). So if you want to perform an action if a test fails, for example, you'd register the callback using onSuccess.

    Here's an example in which withFixture(NoArgAsyncTest) is used to take a snapshot of the working directory if a test fails, and send that information to the standard output stream:

    package org.scalatest.examples.asyncflatspec.noargasynctest
    
    import java.io.File
    import org.scalatest._
    import scala.concurrent.Future
    
    class ExampleSpec extends AsyncFlatSpec {
    
      override def withFixture(test: NoArgAsyncTest) = {
    
        super.withFixture(test) onFailedThen { _ =>
          val currDir = new File(".")
          val fileNames = currDir.list()
          info("Dir snapshot: " + fileNames.mkString(", "))
        }
      }
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "This test" should "succeed" in {
        addSoon(1, 1) map { sum => assert(sum == 2) }
      }
    
      it should "fail" in {
        addSoon(1, 1) map { sum => assert(sum == 3) }
      }
    }
    

    Running this version of ExampleSpec in the interpreter in a directory with two files, hello.txt and world.txt would give the following output:

    scala> org.scalatest.run(new ExampleSpec)
    ExampleSpec:
    This test
    - should succeed
    - should fail *** FAILED ***
      2 did not equal 3 (:33)
    

    Note that the NoArgAsyncTest passed to withFixture, in addition to an apply method that executes the test, also includes the test name and the config map passed to runTest. Thus you can also use the test name and configuration objects in your withFixture implementation.

    Lastly, if you want to transform the outcome in some way in withFixture, you'll need to use either the map or transform methods of Future, like this:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      val futureOutcome = super.withFixture(test) // Invoke the test function
    
      futureOutcome change { outcome =>
        // transform the outcome into a new outcome here
      }
    }
    

    Note that a NoArgAsyncTest's apply method will return a scala.util.Failure only if the test completes abruptly with a "test-fatal" exception (such as OutOfMemoryError) that should cause the suite to abort rather than the test to fail. Thus usually you would use map to transform future outcomes, not transform, so that such test-fatal exceptions pass through unchanged. The suite will abort asynchronously with any exception returned from NoArgAsyncTest's apply method in a scala.util.Failure.

    Calling loan-fixture methods

    If you need to both pass a fixture object into a test and perform cleanup at the end of the test, you'll need to use the loan pattern. If different tests need different fixtures that require cleanup, you can implement the loan pattern directly by writing loan-fixture methods. A loan-fixture method takes a function whose body forms part or all of a test's code. It creates a fixture, passes it to the test code by invoking the function, then cleans up the fixture after the function returns.

    The following example shows three tests that use two fixtures, a database and a file. Both require cleanup after, so each is provided via a loan-fixture method. (In this example, the database is simulated with a StringBuffer.)

    package org.scalatest.examples.asyncflatspec.loanfixture
    
    import java.util.concurrent.ConcurrentHashMap
    
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    object DbServer { // Simulating a database server
      type Db = StringBuffer
      private final val databases = new ConcurrentHashMap[String, Db]
      def createDb(name: String): Db = {
        val db = new StringBuffer // java.lang.StringBuffer is thread-safe
        databases.put(name, db)
        db
      }
      def removeDb(name: String): Unit = {
        databases.remove(name)
      }
    }
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    import org.scalatest._
    import DbServer._
    import java.util.UUID.randomUUID
    
    class ExampleSpec extends AsyncFlatSpec {
    
      def withDatabase(testCode: Future[Db] => Future[Assertion]) = {
        val dbName = randomUUID.toString // generate a unique db name
        val futureDb = Future { createDb(dbName) } // create the fixture
        complete {
          val futurePopulatedDb =
            futureDb map { db =>
              db.append("ScalaTest is ") // perform setup
            }
          testCode(futurePopulatedDb) // "loan" the fixture to the test code
        } lastly {
          removeDb(dbName) // ensure the fixture will be cleaned up
        }
      }
    
      def withActor(testCode: StringActor => Future[Assertion]) = {
        val actor = new StringActor
        complete {
          actor ! Append("ScalaTest is ") // set up the fixture
          testCode(actor) // "loan" the fixture to the test code
        } lastly {
          actor ! Clear // ensure the fixture will be cleaned up
        }
      }
    
      // This test needs the actor fixture
      "Testing" should "be productive" in {
        withActor { actor =>
          actor ! Append("productive!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is productive!")
          }
        }
      }
    
      // This test needs the database fixture
      "Test code" should "be readable" in {
        withDatabase { futureDb =>
          futureDb map { db =>
            db.append("readable!")
            assert(db.toString == "ScalaTest is readable!")
          }
        }
      }
    
      // This test needs both the actor and the database
      it should "be clear and concise" in {
        withDatabase { futureDb =>
          withActor { actor => // loan-fixture methods compose
            actor ! Append("concise!")
            val futureString = actor ? GetValue
            val futurePair: Future[(Db, String)] =
              futureDb zip futureString
            futurePair map { case (db, s) =>
              db.append("clear!")
              assert(db.toString == "ScalaTest is clear!")
              assert(s == "ScalaTest is concise!")
            }
          }
        }
      }
    }
    

    As demonstrated by the last test, loan-fixture methods compose. Not only do loan-fixture methods allow you to give each test the fixture it needs, they allow you to give a test multiple fixtures and clean everything up afterwards.

    Also demonstrated in this example is the technique of giving each test its own "fixture sandbox" to play in. When your fixtures involve external side-effects, like creating databases, it is a good idea to give each database a unique name as is done in this example. This keeps tests completely isolated, allowing you to run them in parallel if desired.

    Overriding withFixture(OneArgTest)

    If all or most tests need the same fixture, you can avoid some of the boilerplate of the loan-fixture method approach by using a fixture.AsyncTestSuite and overriding withFixture(OneArgAsyncTest). Each test in a fixture.AsyncTestSuite takes a fixture as a parameter, allowing you to pass the fixture into the test. You must indicate the type of the fixture parameter by specifying FixtureParam, and implement a withFixture method that takes a OneArgAsyncTest. This withFixture method is responsible for invoking the one-arg async test function, so you can perform fixture set up before invoking and passing the fixture into the test function, and ensure clean up is performed after the test completes.

    To enable the stacking of traits that define withFixture(NoArgAsyncTest), it is a good idea to let withFixture(NoArgAsyncTest) invoke the test function instead of invoking the test function directly. To do so, you'll need to convert the OneArgAsyncTest to a NoArgAsyncTest. You can do that by passing the fixture object to the toNoArgAsyncTest method of OneArgAsyncTest. In other words, instead of writing “test(theFixture)”, you'd delegate responsibility for invoking the test function to the withFixture(NoArgAsyncTest) method of the same instance by writing:

    withFixture(test.toNoArgAsyncTest(theFixture))
    

    Here's a complete example:

    package org.scalatest.examples.asyncflatspec.oneargasynctest
    
    import org.scalatest._
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class ExampleSpec extends fixture.AsyncFlatSpec {
    
      type FixtureParam = StringActor
    
      def withFixture(test: OneArgAsyncTest): FutureOutcome = {
    
        val actor = new StringActor
        complete {
          actor ! Append("ScalaTest is ") // set up the fixture
          withFixture(test.toNoArgAsyncTest(actor))
        } lastly {
          actor ! Clear // ensure the fixture will be cleaned up
        }
      }
    
      "Testing" should "be easy" in { actor =>
        actor ! Append("easy!")
        val futureString = actor ? GetValue
        futureString map { s =>
          assert(s == "ScalaTest is easy!")
        }
      }
    
      it should "be fun" in { actor =>
        actor ! Append("fun!")
        val futureString = actor ? GetValue
        futureString map { s =>
          assert(s == "ScalaTest is fun!")
        }
      }
    }
    

    In this example, the tests required one fixture object, a StringActor. If your tests need multiple fixture objects, you can simply define the FixtureParam type to be a tuple containing the objects or, alternatively, a case class containing the objects. For more information on the withFixture(OneArgAsyncTest) technique, see the documentation for fixture.AsyncFlatSpec.

    Mixing in BeforeAndAfter

    In all the shared fixture examples shown so far, the activities of creating, setting up, and cleaning up the fixture objects have been performed during the test. This means that if an exception occurs during any of these activities, it will be reported as a test failure. Sometimes, however, you may want setup to happen before the test starts, and cleanup after the test has completed, so that if an exception occurs during setup or cleanup, the entire suite aborts and no more tests are attempted. The simplest way to accomplish this in ScalaTest is to mix in trait BeforeAndAfter. With this trait you can denote a bit of code to run before each test with before and/or after each test each test with after, like this:

    package org.scalatest.examples.asyncflatspec.beforeandafter
    
    import org.scalatest.AsyncFlatSpec
    import org.scalatest.BeforeAndAfter
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class ExampleSpec extends AsyncFlatSpec with BeforeAndAfter {
    
      final val actor = new StringActor
    
      before {
        actor ! Append("ScalaTest is ") // set up the fixture
      }
    
      after {
        actor ! Clear // clean up the fixture
      }
    
      "Testing" should "be easy" in {
        actor ! Append("easy!")
        val futureString = actor ? GetValue
        futureString map { s =>
          assert(s == "ScalaTest is easy!")
        }
      }
    
      it should "be fun" in {
        actor ! Append("fun!")
        val futureString = actor ? GetValue
        futureString map { s =>
          assert(s == "ScalaTest is fun!")
        }
      }
    }
    

    Note that the only way before and after code can communicate with test code is via some side-effecting mechanism, commonly by reassigning instance vars or by changing the state of mutable objects held from instance vals (as in this example). If using instance vars or mutable objects held from instance vals you wouldn't be able to run tests in parallel in the same instance of the test class (on the JVM, not Scala.js) unless you synchronized access to the shared, mutable state.

    Note that on the JVM, if you override ScalaTest's default serial execution context, you will likely need to worry about synchronizing access to shared mutable fixture state, because the execution context may assign different threads to process different Future transformations. Although access to mutable state along the same linear chain of Future transformations need not be synchronized, it can be difficult to spot cases where these constraints are violated. The best approach is to use only immutable objects when transforming Futures. When that's not practical, involve only thread-safe mutable objects, as is done in the above example. On Scala.js, by contrast, you need not worry about thread synchronization, because in effect only one thread exists.

    Although BeforeAndAfter provides a minimal-boilerplate way to execute code before and after tests, it isn't designed to enable stackable traits, because the order of execution would be non-obvious. If you want to factor out before and after code that is common to multiple test suites, you should use trait BeforeAndAfterEach instead, as shown later in the next section, composing fixtures by stacking traits.

    Composing fixtures by stacking traits

    In larger projects, teams often end up with several different fixtures that test classes need in different combinations, and possibly initialized (and cleaned up) in different orders. A good way to accomplish this in ScalaTest is to factor the individual fixtures into traits that can be composed using the stackable trait pattern. This can be done, for example, by placing withFixture methods in several traits, each of which call super.withFixture. Here's an example in which the StringBuilderActor and StringBufferActor fixtures used in the previous examples have been factored out into two stackable fixture traits named Builder and Buffer:

    package org.scalatest.examples.asyncflatspec.composingwithasyncfixture
    
    import org.scalatest._
    import org.scalatest.SuiteMixin
    import collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringBuilderActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class StringBufferActor {
      private final val buf = ListBuffer.empty[String]
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => buf += value
            case Clear => buf.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[List[String]] =
        Future {
          synchronized { buf.toList }
        }
    }
    
    trait Builder extends AsyncTestSuiteMixin { this: AsyncTestSuite =>
    
      final val builderActor = new StringBuilderActor
    
      abstract override def withFixture(test: NoArgAsyncTest) = {
        builderActor ! Append("ScalaTest is ")
        complete {
          super.withFixture(test) // To be stackable, must call super.withFixture
        } lastly {
          builderActor ! Clear
        }
      }
    }
    
    trait Buffer extends AsyncTestSuiteMixin { this: AsyncTestSuite =>
    
      final val bufferActor = new StringBufferActor
    
      abstract override def withFixture(test: NoArgAsyncTest) = {
        complete {
          super.withFixture(test) // To be stackable, must call super.withFixture
        } lastly {
          bufferActor ! Clear
        }
      }
    }
    
    class ExampleSpec extends AsyncFlatSpec with Builder with Buffer {
    
      "Testing" should "be easy" in {
        builderActor ! Append("easy!")
        val futureString = builderActor ? GetValue
        val futureList = bufferActor ? GetValue
        val futurePair: Future[(String, List[String])] = futureString zip futureList
        futurePair map { case (str, lst) =>
          assert(str == "ScalaTest is easy!")
          assert(lst.isEmpty)
          bufferActor ! Append("sweet")
          succeed
        }
      }
    
      it should "be fun" in {
        builderActor ! Append("fun!")
        val futureString = builderActor ? GetValue
        val futureList = bufferActor ? GetValue
        val futurePair: Future[(String, List[String])] = futureString zip futureList
        futurePair map { case (str, lst) =>
          assert(str == "ScalaTest is fun!")
          assert(lst.isEmpty)
          bufferActor ! Append("awesome")
          succeed
        }
      }
    }
    

    By mixing in both the Builder and Buffer traits, ExampleSpec gets both fixtures, which will be initialized before each test and cleaned up after. The order the traits are mixed together determines the order of execution. In this case, Builder is “super” to Buffer. If you wanted Buffer to be “super” to Builder, you need only switch the order you mix them together, like this:

    class Example2Spec extends AsyncFlatSpec with Buffer with Builder
    

    If you only need one fixture you mix in only that trait:

    class Example3Spec extends AsyncFlatSpec with Builder
    

    Another way to create stackable fixture traits is by extending the BeforeAndAfterEach and/or BeforeAndAfterAll traits. BeforeAndAfterEach has 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). Similarly, BeforeAndAfterAll has a beforeAll method that will be run before all tests, and an afterAll method that will be run after all tests. Here's what the previously shown example would look like if it were rewritten to use the BeforeAndAfterEach methods instead of withFixture:

    package org.scalatest.examples.asyncflatspec.composingbeforeandaftereach
    
    import org.scalatest._
    import org.scalatest.BeforeAndAfterEach
    import collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringBuilderActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class StringBufferActor {
      private final val buf = ListBuffer.empty[String]
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => buf += value
            case Clear => buf.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[List[String]] =
        Future {
          synchronized { buf.toList }
        }
    }
    
    trait Builder extends BeforeAndAfterEach { this: Suite =>
    
      final val builderActor = new StringBuilderActor
    
      override def beforeEach() {
        builderActor ! 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 builderActor ! Clear
      }
    }
    
    trait Buffer extends BeforeAndAfterEach { this: Suite =>
    
      final val bufferActor = new StringBufferActor
    
      override def afterEach() {
        try super.afterEach() // To be stackable, must call super.afterEach
        finally bufferActor ! Clear
      }
    }
    
    class ExampleSpec extends AsyncFlatSpec with Builder with Buffer {
    
      "Testing" should "be easy" in {
        builderActor ! Append("easy!")
        val futureString = builderActor ? GetValue
        val futureList = bufferActor ? GetValue
        val futurePair: Future[(String, List[String])] = futureString zip futureList
        futurePair map { case (str, lst) =>
          assert(str == "ScalaTest is easy!")
          assert(lst.isEmpty)
          bufferActor ! Append("sweet")
          succeed
        }
      }
    
      it should "be fun" in {
        builderActor ! Append("fun!")
        val futureString = builderActor ? GetValue
        val futureList = bufferActor ? GetValue
        val futurePair: Future[(String, List[String])] = futureString zip futureList
        futurePair map { case (str, lst) =>
          assert(str == "ScalaTest is fun!")
          assert(lst.isEmpty)
          bufferActor ! Append("awesome")
          succeed
        }
      }
    }
    

    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 difference between stacking traits that extend BeforeAndAfterEach versus traits that implement withFixture is that setup and cleanup code happens before and after the test in BeforeAndAfterEach, but at the beginning and end of the test in withFixture. Thus if a withFixture method completes abruptly with an exception, it is considered a failed test. By contrast, if any of the beforeEach or afterEach methods of BeforeAndAfterEach complete abruptly, it is considered an aborted suite, which will result in a SuiteAborted event.

    Shared tests

    Sometimes you may want to run the same test code on different fixture objects. In other words, you may want to write tests that are "shared" by different fixture objects. To accomplish this in an AsyncFlatSpec, you first place shared tests in behavior functions. These behavior functions will be invoked during the construction phase of any AsyncFlatSpec that uses them, so that the tests they contain will be registered as tests in that AsyncFlatSpec. For example, given this StackActor class:

    package org.scalatest.examples.asyncflatspec.sharedtests
    
    import scala.collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Stack operations
    case class Push[T](value: T)
    sealed abstract class StackOp
    case object Pop extends StackOp
    case object Peek extends StackOp
    case object Size extends StackOp
    
    // Stack info
    case class StackInfo[T](top: Option[T], size: Int, max: Int) {
      require(size > 0, "size was less than zero")
      require(max > size, "max was less than size")
      val isFull: Boolean = size == max
      val isEmpty: Boolean = size == 0
    }
    
    class StackActor[T](Max: Int, name: String) {
    
      private final val buf = new ListBuffer[T]
    
      def !(push: Push[T]): Unit =
        synchronized {
          if (buf.size != Max)
            buf.prepend(push.value)
          else
            throw new IllegalStateException("can't push onto a full stack")
        }
    
      def ?(op: StackOp)(implicit c: ExecutionContext): Future[StackInfo[T]] =
        synchronized {
          op match {
            case Pop =>
              Future {
                if (buf.size != 0)
                  StackInfo(Some(buf.remove(0)), buf.size, Max)
                else
                  throw new IllegalStateException("can't pop an empty stack")
              }
            case Peek =>
              Future {
                if (buf.size != 0)
                  StackInfo(Some(buf(0)), buf.size, Max)
                else
                  throw new IllegalStateException("can't peek an empty stack")
              }
            case Size =>
              Future { StackInfo(None, buf.size, Max) }
          }
        }
    
      override def toString: String = name
    }
    

    You may want to test the stack represented by the StackActor class in different states: empty, full, with one item, with one item less than capacity, etc. You may find you have several tests that make sense any time the stack is non-empty. Thus you'd ideally want to run those same tests for three stack fixture objects: a full stack, a stack with a one item, and a stack with one item less than capacity. With shared tests, you can factor these tests out into a behavior function, into which you pass the stack fixture to use when running the tests. So in your AsyncFlatSpec for StackActor, you'd invoke the behavior function three times, passing in each of the three stack fixtures so that the shared tests are run for all three fixtures.

    You can define a behavior function that encapsulates these shared tests inside the AsyncFlatSpec that uses them. If they are shared between different AsyncFlatSpecs, however, you could also define them in a separate trait that is mixed into each AsyncFlatSpec that uses them. For example, here the nonEmptyStackActor behavior function (in this case, a behavior method) is defined in a trait along with another method containing shared tests for non-full stacks:

    import org.scalatest.AsyncFlatSpec
    
    trait AsyncFlatSpecStackBehaviors { this: AsyncFlatSpec =>
    
      def nonEmptyStackActor(createNonEmptyStackActor: => StackActor[Int],
            lastItemAdded: Int, name: String): Unit = {
    
        it should ("return non-empty StackInfo when Size is fired at non-empty stack actor: " + name) in {
          val stackActor = createNonEmptyStackActor
          val futureStackInfo = stackActor ? Size
          futureStackInfo map { stackInfo =>
            assert(!stackInfo.isEmpty)
          }
        }
    
        it should ("return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: " + name) in {
          val stackActor = createNonEmptyStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePeek <- stackActor ? Size
              afterPeek <- stackActor ? Peek
            } yield (beforePeek, afterPeek)
          futurePair map { case (beforePeek, afterPeek) =>
            assert(afterPeek.top == Some(lastItemAdded))
            assert(afterPeek.size == beforePeek.size)
          }
        }
    
        it should ("return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: " + name) in {
          val stackActor = createNonEmptyStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePop <- stackActor ? Size
              afterPop <- stackActor ? Pop
            } yield (beforePop, afterPop)
          futurePair map { case (beforePop, afterPop) =>
            assert(afterPop.top == Some(lastItemAdded))
            assert(afterPop.size == beforePop.size - 1)
          }
        }
      }
    
      def nonFullStackActor(createNonFullStackActor: => StackActor[Int], name: String): Unit = {
    
        it should ("return non-full StackInfo when Size is fired at non-full stack actor: " + name) in {
          val stackActor = createNonFullStackActor
          val futureStackInfo = stackActor ? Size
          futureStackInfo map { stackInfo =>
            assert(!stackInfo.isFull)
          }
        }
    
        it should ("return before and after StackInfo that has existing size + 1 and new item as top when Push is fired at non-full stack actor: " + name) in {
          val stackActor = createNonFullStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePush <- stackActor ? Size
              afterPush <- { stackActor ! Push(7); stackActor ? Peek }
            } yield (beforePush, afterPush)
          futurePair map { case (beforePush, afterPush) =>
            assert(afterPush.top == Some(7))
            assert(afterPush.size == beforePush.size + 1)
          }
        }
      }
    }
    

    Given these behavior functions, you could invoke them directly, but AsyncFlatSpec offers a DSL for the purpose, which looks like this:

    it should behave like nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName)
    it should behave like nonFullStackActor(almostEmptyStackActor, almostEmptyStackActorName)
    

    Here's an example:

    class StackSpec extends AsyncFlatSpec with AsyncFlatSpecStackBehaviors {
    
      val Max = 10
      val LastValuePushed = Max - 1
    
      // Stack fixture creation methods
      val emptyStackActorName = "empty stack actor"
      def emptyStackActor = new StackActor[Int](Max, emptyStackActorName )
    
      val fullStackActorName = "full stack actor"
      def fullStackActor = {
        val stackActor = new StackActor[Int](Max, fullStackActorName )
        for (i <- 0 until Max)
          stackActor ! Push(i)
        stackActor
      }
    
      val almostEmptyStackActorName = "almost empty stack actor"
      def almostEmptyStackActor = {
        val stackActor = new StackActor[Int](Max, almostEmptyStackActorName )
        stackActor ! Push(LastValuePushed)
        stackActor
      }
    
      val almostFullStackActorName = "almost full stack actor"
      def almostFullStackActor = {
        val stackActor = new StackActor[Int](Max, almostFullStackActorName)
        for (i <- 1 to LastValuePushed)
          stackActor ! Push(i)
        stackActor
      }
    
      "A Stack actor (when empty)" should "return empty StackInfo when Size is fired at it" in {
        val stackActor = emptyStackActor
        val futureStackInfo = stackActor ? Size
        futureStackInfo map { stackInfo =>
          assert(stackInfo.isEmpty)
        }
      }
    
      it should "complain when Peek is fired at it" in {
        recoverToSucceededIf[IllegalStateException] {
          emptyStackActor ? Peek
        }
      }
    
      it should "complain when Pop is fired at it" in {
        recoverToSucceededIf[IllegalStateException] {
          emptyStackActor ? Pop
        }
      }
    
      "A Stack actor (when non-empty)" should behave like nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName)
    
      it should behave like nonFullStackActor(almostEmptyStackActor, almostEmptyStackActorName)
    
      it should behave like nonEmptyStackActor(almostFullStackActor, LastValuePushed, almostFullStackActorName)
    
      it should behave like nonFullStackActor(almostFullStackActor, almostFullStackActorName)
    
      "A Stack actor (when full)" should "return full StackInfo when Size is fired at it" in {
        val stackActor = fullStackActor
        val futureStackInfo = stackActor ? Size
        futureStackInfo map { stackInfo =>
          assert(stackInfo.isFull)
        }
      }
    
      it should behave like nonEmptyStackActor(fullStackActor, LastValuePushed, fullStackActorName)
    
      it should "complain when Push is fired at it" in {
        val stackActor = fullStackActor
        assertThrows[IllegalStateException] {
          stackActor ! Push(10)
        }
      }
    }
    

    If you load these classes into the Scala interpreter (with scalatest's JAR file on the class path), and execute it, you'll see:

    scala> org.scalatest.run(new StackSpec)
    StackSpec:
    A Stack actor (when empty)
    - should return empty StackInfo when Size is fired at it
    - should complain when Peek is fired at it
    - should complain when Pop is fired at it
    A Stack actor (when non-empty)
    - should return non-empty StackInfo when Size is fired at non-empty stack actor: almost empty stack actor
    - should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost empty stack actor
    - should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost empty stack actor
    - should return non-full StackInfo when Size is fired at non-full stack actor: almost empty stack actor
    - should return before and after StackInfo that has existing size + 1 and new item as top when Push is fired at non-full stack actor: almost empty stack actor
    - should return non-empty StackInfo when Size is fired at non-empty stack actor: almost full stack actor
    - should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost full stack actor
    - should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost full stack actor
    - should return non-full StackInfo when Size is fired at non-full stack actor: almost full stack actor
    - should return before and after StackInfo that has existing size + 1 and new item as top when Push is fired at non-full stack actor: almost full stack actor
    A Stack actor (when full)
    - should return full StackInfo when Size is fired at it
    - should return non-empty StackInfo when Size is fired at non-empty stack actor: full stack actor
    - should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: full stack actor
    - should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: full stack actor
    - should complain when Push is fired at it
    

    One thing to keep in mind when using shared tests is that in ScalaTest, each test in a suite must have a unique name. If you register the same tests repeatedly in the same suite, one problem you may encounter is an exception at runtime complaining that multiple tests are being registered with the same test name. Although in an AsyncFlatSpec, the behavior of clause is a nesting construct analogous to AsyncFunSpec's describe clause, you many sometimes need to do a bit of extra work to ensure that the test names are unique. If a duplicate test name problem shows up in an AsyncFlatSpec, you'll need to pass in a prefix or suffix string to add to each test name. You can call toString on the shared fixture object, or pass this string the same way you pass any other data needed by the shared tests. This is the approach taken by the previous AsyncFlatSpecStackBehaviors example.

    Given this AsyncFlatSpecStackBehaviors trait, calling it with the almostEmptyStackActor fixture, like this:

    "A Stack actor (when non-empty)" should behave like nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName)
    

    yields test names:

    • A Stack actor (when non-empty) should return non-empty StackInfo when Size is fired at non-empty stack actor: almost empty stack actor
    • A Stack actor (when non-empty) should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost empty stack actor
    • A Stack actor (when non-empty) should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost empty stack actor

    Whereas calling it with the almostFullStackActor fixture, like this:

    it should behave like nonEmptyStackActor(almostFullStackActor, LastValuePushed, almostFullStackActorName)
    

    yields different test names:

    • A Stack actor (when non-empty) should return non-empty StackInfo when Size is fired at non-empty stack actor: almost full stack actor
    • A Stack actor (when non-empty) should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost full stack actor
    • A Stack actor (when non-empty) should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost full stack actor
  10. trait AsyncFlatSpecLike extends AsyncTestSuite with AsyncTestRegistration with ShouldVerb with MustVerb with CanVerb with Informing with Notifying with Alerting with Documenting

    Permalink

    Implementation trait for class AsyncFlatSpec, which facilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.

    Implementation trait for class AsyncFlatSpec, which facilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.

    AsyncFlatSpec 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 AsyncFlatSpec into some other class, you can use this trait instead, because class AsyncFlatSpec does nothing more than extend this trait and add a nice toString implementation.

    See the documentation of the class for a detailed overview of AsyncFlatSpec.

    Annotations
    @JSExportDescendentClasses( true ) @Finders()
  11. abstract class AsyncFreeSpec extends AsyncFreeSpecLike

    Permalink

    Enables testing of asynchronous code without blocking, using a style consistent with traditional FreeSpec tests.

    Enables testing of asynchronous code without blocking, using a style consistent with traditional FreeSpec tests.

    Recommended Usage: AsyncFreeSpec is intended to enable users of FreeSpec to write non-blocking asynchronous tests that are consistent with their traditional FreeSpec tests. Note: AsyncFreeSpec is intended for use in special situations where non-blocking asynchronous testing is needed, with class FreeSpec used for general needs.

    Given a Future returned by the code you are testing, you need not block until the Future completes before performing assertions against its value. You can instead map those assertions onto the Future and return the resulting Future[Assertion] to ScalaTest. The test will complete asynchronously, when the Future[Assertion] completes.

    Here's an example AsyncFreeSpec:

    package org.scalatest.examples.asyncfreespec
    
    import org.scalatest.AsyncFreeSpec
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFreeSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "addSoon" - {
        "will eventually compute a sum of passed Ints" in {
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" - {
        "will immediately compute a sum of passed Ints" in {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    In an AsyncFreeSpec you write a test with a string followed by in and the body of the test in curly braces, like this:

    "will eventually compute a sum of passed Ints" in {
      // ...
    }
    

    You can nest a test inside any number of description clauses, which you write with a string followed by a dash character and a block, like this:

    "addSoon" - {
      // ...
    }
    

    You can nest description clauses as deeply as you want. Because the description clause is denoted with an operator, not a word like should, you are free to structure the text however you wish. In short, you structure an AsyncFreeSpec exactly like a FreeSpec, but with tests having result type Assertion or Future[Assertion]. For more examples of structure, see the documentation for FreeSpec.

    Starting with version 3.0.0, ScalaTest assertions and matchers have result type Assertion. The result type of the first test in the example above, therefore, is Future[Assertion]. For clarity, here's the relevant code in a REPL session:

    scala> import org.scalatest._
    import org.scalatest._
    
    scala> import Assertions._
    import Assertions._
    
    scala> import scala.concurrent.Future
    import scala.concurrent.Future
    
    scala> import scala.concurrent.ExecutionContext
    import scala.concurrent.ExecutionContext
    
    scala> implicit val executionContext = ExecutionContext.Implicits.global
    executionContext: scala.concurrent.ExecutionContextExecutor = [email protected]
    
    scala> def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    addSoon: (addends: Int*)scala.concurrent.Future[Int]
    
    scala> val futureSum: Future[Int] = addSoon(1, 2)
    futureSum: scala.concurrent.Future[Int] = [email protected]
    
    scala> futureSum map { sum => assert(sum == 3) }
    res0: scala.concurrent.Future[org.scalatest.Assertion] = [email protected]
    

    The second test has result type Assertion:

    scala> def addNow(addends: Int*): Int = addends.sum
    addNow: (addends: Int*)Int
    
    scala> val sum: Int = addNow(1, 2)
    sum: Int = 3
    
    scala> assert(sum == 3)
    res1: org.scalatest.Assertion = Succeeded
    

    When AddSpec is constructed, the second test will be implicitly converted to Future[Assertion] and registered. The implicit conversion is from Assertion to Future[Assertion], so you must end synchronous tests in some ScalaTest assertion or matcher expression. If a test would not otherwise end in type Assertion, you can place succeed at the end of the test. succeed, a field in trait Assertions, returns the Succeeded singleton:

    scala> succeed
    res2: org.scalatest.Assertion = Succeeded
    

    Thus placing succeed at the end of a test body will satisfy the type checker:

      "will immediately compute a sum of passed Ints" - {
        val sum: Int = addNow(1, 2)
        assert(sum == 3)
        println("hi") // println has result type Unit
        succeed       // succeed has result type Assertion
      }
    

    An AsyncFreeSpec's lifecycle has two phases: the registration phase and the ready phase. It starts in registration phase and enters ready phase the first time run is called on it. It then remains in ready phase for the remainder of its lifetime.

    Tests can only be registered with the it method while the AsyncFreeSpec is in its registration phase. Any attempt to register a test after the AsyncFreeSpec has entered its ready phase, i.e., after run has been invoked on the AsyncFreeSpec, will be met with a thrown TestRegistrationClosedException. The recommended style of using AsyncFreeSpec is to register tests during object construction as is done in all the examples shown here. If you keep to the recommended style, you should never see a TestRegistrationClosedException.

    Asynchronous execution model

    AsyncFreeSpec extends AsyncTestSuite, which provides an implicit scala.concurrent.ExecutionContext named executionContext. This execution context is used by AsyncFreeSpec to transform the Future[Assertion]s returned by each test into the FutureOutcome returned by the test function passed to withFixture. This ExecutionContext is also intended to be used in the tests, including when you map assertions onto futures.

    On both the JVM and Scala.js, the default execution context provided by ScalaTest's asynchronous testing styles confines execution to a single thread per test. On JavaScript, where single-threaded execution is the only possibility, the default execution context is scala.scalajs.concurrent.JSExecutionContext.Implicits.queue. On the JVM, the default execution context is a serial execution context provided by ScalaTest itself.

    When ScalaTest's serial execution context is called upon to execute a task, that task is recorded in a queue for later execution. For example, one task that will be placed in this queue is the task that transforms the Future[Assertion] returned by an asynchronous test body to the FutureOutcome returned from the test function. Other tasks that will be queued are any transformations of, or callbacks registered on, Futures that occur in your test body, including any assertions you map onto Futures. Once the test body returns, the thread that executed the test body will execute the tasks in that queue one after another, in the order they were enqueued.

    ScalaTest provides its serial execution context as the default on the JVM for three reasons. First, most often running both tests and suites in parallel does not give a significant performance boost compared to just running suites in parallel. Thus parallel execution of Future transformations within individual tests is not generally needed for performance reasons.

    Second, if multiple threads are operating in the same suite concurrently, you'll need to make sure access to any mutable fixture objects by multiple threads is synchronized. Although access to mutable state along the same linear chain of Future transformations need not be synchronized, this does not hold true for callbacks, and in general it is easy to make a mistake. Simply put: synchronizing access to shared mutable state is difficult and error prone. Because ScalaTest's default execution context on the JVM confines execution of Future transformations and call backs to a single thread, you need not (by default) worry about synchronizing access to mutable state in your asynchronous-style tests.

    Third, asynchronous-style tests need not be complete when the test body returns, because the test body returns a Future[Assertion]. This Future[Assertion] will often represent a test that has not yet completed. As a result, when using a more traditional execution context backed by a thread-pool, you could potentially start many more tests executing concurrently than there are threads in the thread pool. The more concurrently execute tests you have competing for threads from the same limited thread pool, the more likely it will be that tests will intermitently fail due to timeouts.

    Using ScalaTest's serial execution context on the JVM will ensure the same thread that produced the Future[Assertion] returned from a test body is also used to execute any tasks given to the execution context while executing the test body—and that thread will not be allowed to do anything else until the test completes. If the serial execution context's task queue ever becomes empty while the Future[Assertion] returned by that test's body has not yet completed, the thread will block until another task for that test is enqueued. Although it may seem counter-intuitive, this blocking behavior means the total number of tests allowed to run concurrently will be limited to the total number of threads executing suites. This fact means you can tune the thread pool such that maximum performance is reached while avoiding (or at least, reducing the likelihood of) tests that fail due to timeouts because of thread competition.

    This thread confinement strategy does mean, however, that when you are using the default execution context on the JVM, you must be sure to never block in the test body waiting for a task to be completed by the execution context. If you block, your test will never complete. This kind of problem will be obvious, because the test will consistently hang every time you run it. (If a test is hanging, and you're not sure which one it is, enable slowpoke notifications.) If you really do want to block in your tests, you may wish to just use a traditional FreeSpec with ScalaFutures instead. Alternatively, you could override the executionContext and use a traditional ExecutionContext backed by a thread pool. This will enable you to block in an asynchronous-style test on the JVM, but you'll need to worry about synchronizing access to shared mutable state.

    To use a different execution context, just override executionContext. For example, if you prefer to use the runNow execution context on Scala.js instead of the default queue, you would write:

    // on Scala.js
    implicit override def executionContext =
        scala.scalajs.concurrent.JSExecutionContext.Implicits.runNow
    

    If you prefer on the JVM to use the global execution context, which is backed by a thread pool, instead of ScalaTest's default serial execution contex, which confines execution to a single thread, you would write:

    // on the JVM (and also compiles on Scala.js, giving
    // you the queue execution context)
    implicit override def executionContext =
        scala.concurrent.ExecutionContext.Implicits.global
    

    Serial and parallel test execution

    By default (unless you mix in ParallelTestExecution), tests in an AsyncFreeSpec will be executed one after another, i.e., serially. This is true whether those tests return Assertion or Future[Assertion], no matter what threads are involved. This default behavior allows you to re-use a shared fixture, such as an external database that needs to be cleaned after each test, in multiple tests in async-style suites. This is implemented by registering each test, other than the first test, to run as a continuation after the previous test completes.

    If you want the tests of an AsyncFreeSpec to be executed in parallel, you must mix in ParallelTestExecution and enable parallel execution of tests in your build. You enable parallel execution in Runner with the -P command line flag. In the ScalaTest Maven Plugin, set parallel to true. In sbt, parallel execution is the default, but to be explicit you can write:

    parallelExecution in Test := true // the default in sbt
    

    On the JVM, if both ParallelTestExecution is mixed in and parallel execution is enabled in the build, tests in an async-style suite will be started in parallel, using threads from the Distributor, and allowed to complete in parallel, using threads from the executionContext. If you are using ScalaTest's serial execution context, the JVM default, asynchronous tests will run in parallel very much like traditional (such as FreeSpec) tests run in parallel: 1) Because ParallelTestExecution extends OneInstancePerTest, each test will run in its own instance of the test class, you need not worry about synchronizing access to mutable instance state shared by different tests in the same suite. 2) Because the serial execution context will confine the execution of each test to the single thread that executes the test body, you need not worry about synchronizing access to shared mutable state accessed by transformations and callbacks of Futures inside the test.

    If ParallelTestExecution is mixed in but parallel execution of suites is not enabled, asynchronous tests on the JVM will be started sequentially, by the single thread that invoked run, but without waiting for one test to complete before the next test is started. As a result, asynchronous tests will be allowed to complete in parallel, using threads from the executionContext. If you are using the serial execution context, however, you'll see the same behavior you see when parallel execution is disabled and a traditional suite that mixes in ParallelTestExecution is executed: the tests will run sequentially. If you use an execution context backed by a thread-pool, such as global, however, even though tests will be started sequentially by one thread, they will be allowed to run concurrently using threads from the execution context's thread pool.

    The latter behavior is essentially what you'll see on Scala.js when you execute a suite that mixes in ParallelTestExecution. Because only one thread exists when running under JavaScript, you can't "enable parallel execution of suites." However, it may still be useful to run tests in parallel on Scala.js, because tests can invoke API calls that are truly asynchronous by calling into external APIs that take advantage of non-JavaScript threads. Thus on Scala.js, ParallelTestExecution allows asynchronous tests to run in parallel, even though they must be started sequentially. This may give you better performance when you are using API calls in your Scala.js tests that are truly asynchronous.

    Futures and expected exceptions

    If you need to test for expected exceptions in the context of futures, you can use the recoverToSucceededIf and recoverToExceptionIf methods of trait RecoverMethods. Because this trait is mixed into supertrait AsyncTestSuite, both of these methods are available by default in an AsyncFreeSpec.

    If you just want to ensure that a future fails with a particular exception type, and do not need to inspect the exception further, use recoverToSucceededIf:

    recoverToSucceededIf[IllegalStateException] { // Result type: Future[Assertion]
      emptyStackActor ? Peek
    }
    

    The recoverToSucceededIf method performs a job similar to assertThrows, except in the context of a future. It transforms a Future of any type into a Future[Assertion] that succeeds only if the original future fails with the specified exception. Here's an example in the REPL:

    scala> import org.scalatest.RecoverMethods._
    import org.scalatest.RecoverMethods._
    
    scala> import scala.concurrent.Future
    import scala.concurrent.Future
    
    scala> import scala.concurrent.ExecutionContext.Implicits.global
    import scala.concurrent.ExecutionContext.Implicits.global
    
    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { throw new IllegalStateException }
         | }
    res0: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res0.value
    res1: Option[scala.util.Try[org.scalatest.Assertion]] = Some(Success(Succeeded))
    

    Otherwise it fails with an error message similar to those given by assertThrows:

    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { throw new RuntimeException }
         | }
    res2: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res2.value
    res3: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: Expected exception
          java.lang.IllegalStateException to be thrown, but java.lang.RuntimeException
          was thrown))
    
    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { 42 }
         | }
    res4: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res4.value
    res5: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: Expected exception
          java.lang.IllegalStateException to be thrown, but no exception was thrown))
    

    The recoverToExceptionIf method differs from the recoverToSucceededIf in its behavior when the assertion succeeds: recoverToSucceededIf yields a Future[Assertion], whereas recoverToExceptionIf yields a Future[T], where T is the expected exception type.

    recoverToExceptionIf[IllegalStateException] { // Result type: Future[IllegalStateException]
      emptyStackActor ? Peek
    }
    

    In other words, recoverToExpectionIf is to intercept as recovertToSucceededIf is to assertThrows. The first one allows you to perform further assertions on the expected exception. The second one gives you a result type that will satisfy the type checker at the end of the test body. Here's an example showing recoverToExceptionIf in the REPL:

    scala> val futureEx =
         |   recoverToExceptionIf[IllegalStateException] {
         |     Future { throw new IllegalStateException("hello") }
         |   }
    futureEx: scala.concurrent.Future[IllegalStateException] = ...
    
    scala> futureEx.value
    res6: Option[scala.util.Try[IllegalStateException]] =
        Some(Success(java.lang.IllegalStateException: hello))
    
    scala> futureEx map { ex => assert(ex.getMessage == "world") }
    res7: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res7.value
    res8: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: "[hello]" did not equal "[world]"))
    

    Ignored tests

    To support the common use case of temporarily disabling a test, with the good intention of resurrecting the test at a later time, AsyncFreeSpec adds a method ignore to strings that can be used instead of in to register a test. For example, to temporarily disable the test with the name "addSoon will eventually compute a sum of passed Ints", just change “in” into “ignore,” like this:

    package org.scalatest.examples.asyncfreespec.ignore
    
    import org.scalatest.AsyncFreeSpec
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFreeSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "addSoon" - {
        "will eventually compute a sum of passed Ints" ignore {
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" - {
        "will immediately compute a sum of passed Ints" in {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    If you run this version of AddSpec with:

    scala> org.scalatest.run(new AddSpec)
    

    It will run only the second test and report that the first test was ignored:

    AddSpec:
    addSoon
    - will eventually compute a sum of passed Ints !!! IGNORED !!!
    addNow
    - will immediately compute a sum of passed Ints
    

    If you wish to temporarily ignore an entire suite of tests, you can (on the JVM, not Scala.js) annotate the test class with @Ignore, like this:

    package org.scalatest.examples.asyncfreespec.ignoreall
    
    import org.scalatest.AsyncFreeSpec
    import scala.concurrent.Future
    import org.scalatest.Ignore
    
    @Ignore
    class AddSpec extends AsyncFreeSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "addSoon" - {
        "will eventually compute a sum of passed Ints" in {
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" - {
        "will immediately compute a sum of passed Ints" in {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    When you mark a test class with a tag annotation, ScalaTest will mark each test defined in that class with that tag. Thus, marking the AddSpec in the above example with the @Ignore tag annotation means that both tests in the class will be ignored. If you run the above AddSpec in the Scala interpreter, you'll see:

    AddSpec:
    addSoon
    - will eventually compute a sum of passed Ints !!! IGNORED !!!
    addNow
    - will immediately compute a sum of passed Ints !!! IGNORED !!!
    

    Note that marking a test class as ignored won't prevent it from being discovered by ScalaTest. Ignored classes will be discovered and run, and all their tests will be reported as ignored. This is intended to keep the ignored class visible, to encourage the developers to eventually fix and “un-ignore” it. If you want to prevent a class from being discovered at all (on the JVM, not Scala.js), use the DoNotDiscover annotation instead.

    If you want to ignore all tests of a suite on Scala.js, where annotations can't be inspected at runtime, you'll need to change it to ignore at each test site. To make a suite non-discoverable on Scala.js, ensure it does not declare a public no-arg constructor. You can either declare a public constructor that takes one or more arguments, or make the no-arg constructor non-public. Because this technique will also make the suite non-discoverable on the JVM, it is a good approach for suites you want to run (but not be discoverable) on both Scala.js and the JVM.

    Informers

    One of the parameters to AsyncFreeSpec's run method is a Reporter, which will collect and report information about the running suite of tests. Information about suites and tests that were run, whether tests succeeded or failed, and tests that were ignored will be passed to the Reporter as the suite runs. Most often the reporting done by default by AsyncFreeSpec's methods will be sufficient, but occasionally you may wish to provide custom information to the Reporter from a test. For this purpose, an Informer that will forward information to the current Reporter is provided via the info parameterless method. You can pass the extra information to the Informer via its apply method. The Informer will then pass the information to the Reporter via an InfoProvided event.

    One use case for the Informer is to pass more information about a specification to the reporter. For example, the GivenWhenThen trait provides methods that use the implicit info provided by AsyncFreeSpec to pass such information to the reporter. Here's an example:

    package org.scalatest.examples.asyncfreespec.info
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends AsyncFreeSpec with GivenWhenThen {
    
      "A mutable Set" - {
        "should allow an element to be added" in {
          Given("an empty mutable Set")
          val set = mutable.Set.empty[String]
    
          When("an element is added")
          set += "clarity"
    
          Then("the Set should have size 1")
          assert(set.size === 1)
    
          And("the Set should contain the added element")
          assert(set.contains("clarity"))
    
          info("That's all folks!")
          succeed
        }
      }
    }
    

    If you run this AsyncFreeSpec from the interpreter, you will see the following output:

    scala> org.scalatest.run(new SetSpec)
    A mutable Set
    - should allow an element to be added
      + Given an empty mutable Set
      + When an element is added
      + Then the Set should have size 1
      + And the Set should contain the added element
      + That's all folks! 
    

    Documenters

    AsyncFreeSpec also provides a markup method that returns a Documenter, which allows you to send to the Reporter text formatted in Markdown syntax. You can pass the extra information to the Documenter via its apply method. The Documenter will then pass the information to the Reporter via an MarkupProvided event.

    Here's an example AsyncFreeSpec that uses markup:

    package org.scalatest.examples.asyncfreespec.markup
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends AsyncFreeSpec with GivenWhenThen {
    
      markup { """
    
    Mutable Set
    -----------
    
    A set is a collection that contains no duplicate elements.
    
    To implement a concrete mutable set, you need to provide implementations
    of the following methods:
    
        def contains(elem: A): Boolean
        def iterator: Iterator[A]
        def += (elem: A): this.type
        def -= (elem: A): this.type
    
    If you wish that methods like `take`,
    `drop`, `filter` return the same kind of set,
    you should also override:
    
        def empty: This
    
    It is also good idea to override methods `foreach` and
    `size` for efficiency.
    
      """ }
    
      "A mutable Set" - {
        "should allow an element to be added" in {
          Given("an empty mutable Set")
          val set = mutable.Set.empty[String]
    
          When("an element is added")
          set += "clarity"
    
          Then("the Set should have size 1")
          assert(set.size === 1)
    
          And("the Set should contain the added element")
          assert(set.contains("clarity"))
    
          markup("This test finished with a **bold** statement!")
          succeed
        }
      }
    }
    

    Although all of ScalaTest's built-in reporters will display the markup text in some form, the HTML reporter will format the markup information into HTML. Thus, the main purpose of markup is to add nicely formatted text to HTML reports. Here's what the above SetSpec would look like in the HTML reporter:

    Notifiers and alerters

    ScalaTest records text passed to info and markup during tests, and sends the recorded text in the recordedEvents field of test completion events like TestSucceeded and TestFailed. This allows string reporters (like the standard out reporter) to show info and markup text after the test name in a color determined by the outcome of the test. For example, if the test fails, string reporters will show the info and markup text in red. If a test succeeds, string reporters will show the info and markup text in green. While this approach helps the readability of reports, it means that you can't use info to get status updates from long running tests.

    To get immediate (i.e., non-recorded) notifications from tests, you can use note (a Notifier) and alert (an Alerter). Here's an example showing the differences:

    package org.scalatest.examples.asyncfreespec.note
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends AsyncFreeSpec {
    
      "A mutable Set" - {
        "should allow an element to be added" in {
    
          info("info is recorded")
          markup("markup is *also* recorded")
          note("notes are sent immediately")
          alert("alerts are also sent immediately")
    
          val set = mutable.Set.empty[String]
          set += "clarity"
          assert(set.size === 1)
          assert(set.contains("clarity"))
        }
      }
    }
    

    scala> org.scalatest.run(new SetSpec)
    SetSpec:
     A mutable Set
       + notes are sent immediately
       + alerts are also sent immediately
     - should allow an element to be added
       + info is recorded
       + markup is *also* recorded
    

    Another example is slowpoke notifications. If you find a test is taking a long time to complete, but you're not sure which test, you can enable slowpoke notifications. ScalaTest will use an Alerter to fire an event whenever a test has been running longer than a specified amount of time.

    In summary, use info and markup for text that should form part of the specification output. Use note and alert to send status notifications. (Because the HTML reporter is intended to produce a readable, printable specification, info and markup text will appear in the HTML report, but note and alert text will not.)

    Pending tests

    A pending test is one that has been given a name but is not yet implemented. The purpose of pending tests is to facilitate a style of testing in which documentation of behavior is sketched out before tests are written to verify that behavior (and often, before the behavior of the system being tested is itself implemented). Such sketches form a kind of specification of what tests and functionality to implement later.

    To support this style of testing, a test can be given a name that specifies one bit of behavior required by the system being tested. At the end of the test, it can call method pending, which will cause it to complete abruptly with TestPendingException.

    Because tests in ScalaTest can be designated as pending with TestPendingException, both the test name and any information sent to the reporter when running the test can appear in the report of a test run. (In other words, the code of a pending test is executed just like any other test.) However, because the test completes abruptly with TestPendingException, the test will be reported as pending, to indicate the actual test, and possibly the functionality, has not yet been implemented. Here's an example:

    package org.scalatest.examples.asyncfreespec.pending
    
    import org.scalatest.AsyncFreeSpec
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFreeSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "addSoon" - {
        "will eventually compute a sum of passed Ints" in (pending)
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" - {
        "will immediately compute a sum of passed Ints" in {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    (Note: "(pending)" is the body of the test. Thus the test contains just one statement, an invocation of the pending method, which throws TestPendingException.) If you run this version of AddSpec with:

    scala> org.scalatest.run(new AddSpec)
    

    It will run both tests, but report that first test is pending. You'll see:

    AddSpec:
    addSoon
    - will eventually compute a sum of passed Ints (pending)
    addNow
    - will immediately compute a sum of passed Ints
    

    One difference between an ignored test and a pending one is that an ignored test is intended to be used during significant refactorings of the code under test, when tests break and you don't want to spend the time to fix all of them immediately. You can mark some of those broken tests as ignored temporarily, so that you can focus the red bar on just failing tests you actually want to fix immediately. Later you can go back and fix the ignored tests. In other words, by ignoring some failing tests temporarily, you can more easily notice failed tests that you actually want to fix. By contrast, a pending test is intended to be used before a test and/or the code under test is written. Pending indicates you've decided to write a test for a bit of behavior, but either you haven't written the test yet, or have only written part of it, or perhaps you've written the test but don't want to implement the behavior it tests until after you've implemented a different bit of behavior you realized you need first. Thus ignored tests are designed to facilitate refactoring of existing code whereas pending tests are designed to facilitate the creation of new code.

    One other difference between ignored and pending tests is that ignored tests are implemented as a test tag that is excluded by default. Thus an ignored test is never executed. By contrast, a pending test is implemented as a test that throws TestPendingException (which is what calling the pending method does). Thus the body of pending tests are executed up until they throw TestPendingException.

    Tagging tests

    An AsyncFreeSpec's tests may be classified into groups by tagging them with string names. As with any suite, when executing an AsyncFreeSpec, groups of tests can optionally be included and/or excluded. To tag an AsyncFreeSpec's tests, you pass objects that extend class org.scalatest.Tag to methods that register tests. Class Tag takes one parameter, a string name. If you have created tag annotation interfaces as described in the Tag documentation, then you will probably want to use tag names on your test functions that match. To do so, simply pass the fully qualified names of the tag interfaces to the Tag constructor. For example, if you've defined a tag annotation interface with fully qualified name, com.mycompany.tags.DbTest, then you could create a matching tag for AsyncFreeSpecs like this:

    package org.scalatest.examples.asyncfreespec.tagging
    
    import org.scalatest.Tag
    
    object DbTest extends Tag("com.mycompany.tags.DbTest")
    

    Given these definitions, you could place AsyncFreeSpec tests into groups with tags like this:

    import org.scalatest.AsyncFreeSpec
    import org.scalatest.tagobjects.Slow
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFreeSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "addSoon" - {
        "will eventually compute a sum of passed Ints" taggedAs(Slow) in {
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" - {
        "will immediately compute a sum of passed Ints" taggedAs(Slow, DbTest) in {
    
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    This code marks both tests with the org.scalatest.tags.Slow tag, and the second test with the com.mycompany.tags.DbTest tag.

    The run method takes a Filter, whose constructor takes an optional Set[String] called tagsToInclude and a Set[String] called tagsToExclude. If tagsToInclude is None, all tests will be run except those those belonging to tags listed in the tagsToExclude Set. If tagsToInclude is defined, only tests belonging to tags mentioned in the tagsToInclude set, and not mentioned in tagsToExclude, will be run.

    It is recommended, though not required, that you create a corresponding tag annotation when you create a Tag object. A tag annotation (on the JVM, not Scala.js) allows you to tag all the tests of an AsyncFreeSpec in one stroke by annotating the class. For more information and examples, see the documentation for class Tag. On Scala.js, to tag all tests of a suite, you'll need to tag each test individually at the test site.

    Shared fixtures

    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.

    ScalaTest recommends three techniques to eliminate such code duplication in async styles:

    • Refactor using Scala
    • Override withFixture
    • Mix in a before-and-after trait

    Each technique is geared towards helping you reduce code duplication without introducing instance vars, shared mutable objects, or other dependencies between tests. Eliminating shared mutable state across tests will make your test code easier to reason about and eliminate the need to synchronize access to shared mutable state on the JVM.

    The following sections describe these techniques, including explaining the recommended usage for each. But first, here's a table summarizing the options:

    Refactor using Scala when different tests need different fixtures.
    get-fixture methods The extract method refactor helps you create a fresh instances of mutable fixture objects in each test that needs them, but doesn't help you clean them up when you're done.
    loan-fixture methods Factor out dupicate code with the loan pattern when different tests need different fixtures that must be cleaned up afterwards.
    Override withFixture when most or all tests need the same fixture.
    withFixture(NoArgAsyncTest) The recommended default approach when most or all tests need the same fixture treatment. This general technique allows you, for example, to perform side effects at the beginning and end of all or most tests, transform the outcome of tests, retry tests, make decisions based on test names, tags, or other test data. Use this technique unless:
    Different tests need different fixtures (refactor using Scala instead)
    An exception in fixture code should abort the suite, not fail the test (use a before-and-after trait instead)
    You have objects to pass into tests (override withFixture(OneArgAsyncTest) instead)
    withFixture(OneArgAsyncTest) Use when you want to pass the same fixture object or objects as a parameter into all or most tests.
    Mix in a before-and-after trait when you want an aborted suite, not a failed test, if the fixture code fails.
    BeforeAndAfter Use this boilerplate-buster when you need to perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.
    BeforeAndAfterEach Use when you want to stack traits that perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.

    Calling get-fixture methods

    If you need to create the same mutable fixture objects in multiple tests, and don't need to clean them up after using them, the simplest approach is to write one or more get-fixture methods. A get-fixture method returns a new instance of a needed fixture object (or a holder object containing multiple fixture objects) each time it is called. You can call a get-fixture method at the beginning of each test that needs the fixture, storing the returned object or objects in local variables. Here's an example:

    package org.scalatest.examples.asyncfreespec.getfixture
    
    import org.scalatest.AsyncFreeSpec
    import scala.concurrent.Future
    
    class ExampleSpec extends AsyncFreeSpec {
    
      def fixture: Future[String] = Future { "ScalaTest is " }
    
      "Testing" - {
        "should be easy" in {
          val future = fixture
          val result = future map { s => s + "easy!" }
          result map { s =>
            assert(s == "ScalaTest is easy!")
          }
        }
    
        "should be fun" in {
          val future = fixture
          val result = future map { s => s + "fun!" }
          result map { s =>
            assert(s == "ScalaTest is fun!")
          }
        }
      }
    }
    

    If you need to configure fixture objects differently in different tests, you can pass configuration into the get-fixture method. For example, you could pass in an initial value for a fixture object as a parameter to the get-fixture method.

    Overriding withFixture(NoArgAsyncTest)

    Although the get-fixture method approach takes care of setting up a fixture at the beginning of each test, it doesn't address the problem of cleaning up a fixture at the end of the test. If you just need to perform a side-effect at the beginning or end of a test, and don't need to actually pass any fixture objects into the test, you can override withFixture(NoArgAsyncTest), a method defined in trait AsyncTestSuite, a supertrait of AsyncFreeSpec.

    Trait AsyncFreeSpec's runTest method passes a no-arg async test function to withFixture(NoArgAsyncTest). It is withFixture's responsibility to invoke that test function. The default implementation of withFixture simply invokes the function and returns the result, like this:

    // Default implementation in trait AsyncTestSuite
    protected def withFixture(test: NoArgAsyncTest): FutureOutcome = {
      test()
    }
    

    You can, therefore, override withFixture to perform setup before invoking the test function, and/or perform cleanup after the test completes. The recommended way to ensure cleanup is performed after a test completes is to use the complete-lastly syntax, defined in supertrait CompleteLastly. The complete-lastly syntax will ensure that cleanup will occur whether future-producing code completes abruptly by throwing an exception, or returns normally yielding a future. In the latter case, complete-lastly will register the cleanup code to execute asynchronously when the future completes.

    The withFixture method is designed to be stacked, and to enable this, you should always call the super implementation of withFixture, 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)”, like this:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      complete {
        super.withFixture(test) // Invoke the test function
      } lastly {
        // Perform cleanup here
      }
    }
    

    If you have no cleanup to perform, you can write withFixture like this instead:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      super.withFixture(test) // Invoke the test function
    }
    

    If you want to perform an action only for certain outcomes, you'll need to register code performing that action as a callback on the Future using one of Future's registration methods: onComplete, onSuccess, or onFailure. Note that if a test fails, that will be treated as a scala.util.Success(org.scalatest.Failed). So if you want to perform an action if a test fails, for example, you'd register the callback using onSuccess.

    Here's an example in which withFixture(NoArgAsyncTest) is used to take a snapshot of the working directory if a test fails, and send that information to the standard output stream:

    package org.scalatest.examples.asyncfreespec.noargasynctest
    
    import java.io.File
    import org.scalatest._
    import scala.concurrent.Future
    
    class ExampleSpec extends AsyncFreeSpec {
    
      override def withFixture(test: NoArgAsyncTest) = {
    
        super.withFixture(test) onFailedThen { _ =>
          val currDir = new File(".")
          val fileNames = currDir.list()
          info("Dir snapshot: " + fileNames.mkString(", "))
        }
      }
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "This test" - {
        "should succeed" in {
          addSoon(1, 1) map { sum => assert(sum == 2) }
        }
    
        "should fail" in {
          addSoon(1, 1) map { sum => assert(sum == 3) }
        }
      }
    }
    

    Running this version of ExampleSpec in the interpreter in a directory with two files, hello.txt and world.txt would give the following output:

    scala> org.scalatest.run(new ExampleSpec)
    ExampleSpec:
    This test
    - should succeed
    - should fail *** FAILED ***
      2 did not equal 3 (:33)
    

    Note that the NoArgAsyncTest passed to withFixture, in addition to an apply method that executes the test, also includes the test name and the config map passed to runTest. Thus you can also use the test name and configuration objects in your withFixture implementation.

    Lastly, if you want to transform the outcome in some way in withFixture, you'll need to use either the map or transform methods of Future, like this:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      val futureOutcome = super.withFixture(test) // Invoke the test function
    
      futureOutcome change { outcome =>
        // transform the outcome into a new outcome here
      }
    }
    

    Note that a NoArgAsyncTest's apply method will return a scala.util.Failure only if the test completes abruptly with a "test-fatal" exception (such as OutOfMemoryError) that should cause the suite to abort rather than the test to fail. Thus usually you would use map to transform future outcomes, not transform, so that such test-fatal exceptions pass through unchanged. The suite will abort asynchronously with any exception returned from NoArgAsyncTest's apply method in a scala.util.Failure.

    Calling loan-fixture methods

    If you need to both pass a fixture object into a test and perform cleanup at the end of the test, you'll need to use the loan pattern. If different tests need different fixtures that require cleanup, you can implement the loan pattern directly by writing loan-fixture methods. A loan-fixture method takes a function whose body forms part or all of a test's code. It creates a fixture, passes it to the test code by invoking the function, then cleans up the fixture after the function returns.

    The following example shows three tests that use two fixtures, a database and a file. Both require cleanup after, so each is provided via a loan-fixture method. (In this example, the database is simulated with a StringBuffer.)

    package org.scalatest.examples.asyncfreespec.loanfixture
    
    import java.util.concurrent.ConcurrentHashMap
    
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    object DbServer { // Simulating a database server
      type Db = StringBuffer
      private final val databases = new ConcurrentHashMap[String, Db]
      def createDb(name: String): Db = {
        val db = new StringBuffer // java.lang.StringBuffer is thread-safe
        databases.put(name, db)
        db
      }
      def removeDb(name: String): Unit = {
        databases.remove(name)
      }
    }
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    import org.scalatest._
    import DbServer._
    import java.util.UUID.randomUUID
    
    class ExampleSpec extends AsyncFreeSpec {
    
      def withDatabase(testCode: Future[Db] => Future[Assertion]) = {
        val dbName = randomUUID.toString // generate a unique db name
        val futureDb = Future { createDb(dbName) } // create the fixture
        complete {
          val futurePopulatedDb =
            futureDb map { db =>
              db.append("ScalaTest is ") // perform setup
            }
          testCode(futurePopulatedDb) // "loan" the fixture to the test code
        } lastly {
          removeDb(dbName) // ensure the fixture will be cleaned up
        }
      }
    
      def withActor(testCode: StringActor => Future[Assertion]) = {
        val actor = new StringActor
        complete {
          actor ! Append("ScalaTest is ") // set up the fixture
          testCode(actor) // "loan" the fixture to the test code
        } lastly {
          actor ! Clear // ensure the fixture will be cleaned up
        }
      }
    
      "Testing" - {
        // This test needs the actor fixture
        "should be productive" in {
          withActor { actor =>
            actor ! Append("productive!")
            val futureString = actor ? GetValue
            futureString map { s =>
              assert(s == "ScalaTest is productive!")
            }
          }
        }
      }
    
      "Test code" - {
        // This test needs the database fixture
        "should be readable" in {
          withDatabase { futureDb =>
            futureDb map { db =>
              db.append("readable!")
              assert(db.toString == "ScalaTest is readable!")
            }
          }
        }
    
        // This test needs both the actor and the database
        "should be clear and concise" in {
          withDatabase { futureDb =>
            withActor { actor => // loan-fixture methods compose
              actor ! Append("concise!")
              val futureString = actor ? GetValue
              val futurePair: Future[(Db, String)] =
                futureDb zip futureString
              futurePair map { case (db, s) =>
                db.append("clear!")
                assert(db.toString == "ScalaTest is clear!")
                assert(s == "ScalaTest is concise!")
              }
            }
          }
        }
      }
    }
    

    As demonstrated by the last test, loan-fixture methods compose. Not only do loan-fixture methods allow you to give each test the fixture it needs, they allow you to give a test multiple fixtures and clean everything up afterwards.

    Also demonstrated in this example is the technique of giving each test its own "fixture sandbox" to play in. When your fixtures involve external side-effects, like creating databases, it is a good idea to give each database a unique name as is done in this example. This keeps tests completely isolated, allowing you to run them in parallel if desired.

    Overriding withFixture(OneArgTest)

    If all or most tests need the same fixture, you can avoid some of the boilerplate of the loan-fixture method approach by using a fixture.AsyncTestSuite and overriding withFixture(OneArgAsyncTest). Each test in a fixture.AsyncTestSuite takes a fixture as a parameter, allowing you to pass the fixture into the test. You must indicate the type of the fixture parameter by specifying FixtureParam, and implement a withFixture method that takes a OneArgAsyncTest. This withFixture method is responsible for invoking the one-arg async test function, so you can perform fixture set up before invoking and passing the fixture into the test function, and ensure clean up is performed after the test completes.

    To enable the stacking of traits that define withFixture(NoArgAsyncTest), it is a good idea to let withFixture(NoArgAsyncTest) invoke the test function instead of invoking the test function directly. To do so, you'll need to convert the OneArgAsyncTest to a NoArgAsyncTest. You can do that by passing the fixture object to the toNoArgAsyncTest method of OneArgAsyncTest. In other words, instead of writing “test(theFixture)”, you'd delegate responsibility for invoking the test function to the withFixture(NoArgAsyncTest) method of the same instance by writing:

    withFixture(test.toNoArgAsyncTest(theFixture))
    

    Here's a complete example:

    package org.scalatest.examples.asyncfreespec.oneargasynctest
    
    import org.scalatest._
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class ExampleSpec extends fixture.AsyncFreeSpec {
    
      type FixtureParam = StringActor
    
      def withFixture(test: OneArgAsyncTest): FutureOutcome = {
    
        val actor = new StringActor
        complete {
          actor ! Append("ScalaTest is ") // set up the fixture
          withFixture(test.toNoArgAsyncTest(actor))
        } lastly {
          actor ! Clear // ensure the fixture will be cleaned up
        }
      }
    
      "Testing" - {
        "should be easy" in { actor =>
          actor ! Append("easy!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is easy!")
          }
        }
    
        "should be fun" in { actor =>
          actor ! Append("fun!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is fun!")
          }
        }
      }
    }
    

    In this example, the tests required one fixture object, a StringActor. If your tests need multiple fixture objects, you can simply define the FixtureParam type to be a tuple containing the objects or, alternatively, a case class containing the objects. For more information on the withFixture(OneArgAsyncTest) technique, see the documentation for fixture.AsyncFreeSpec.

    Mixing in BeforeAndAfter

    In all the shared fixture examples shown so far, the activities of creating, setting up, and cleaning up the fixture objects have been performed during the test. This means that if an exception occurs during any of these activities, it will be reported as a test failure. Sometimes, however, you may want setup to happen before the test starts, and cleanup after the test has completed, so that if an exception occurs during setup or cleanup, the entire suite aborts and no more tests are attempted. The simplest way to accomplish this in ScalaTest is to mix in trait BeforeAndAfter. With this trait you can denote a bit of code to run before each test with before and/or after each test each test with after, like this:

    package org.scalatest.examples.asyncfreespec.beforeandafter
    
    import org.scalatest.AsyncFreeSpec
    import org.scalatest.BeforeAndAfter
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class ExampleSpec extends AsyncFreeSpec with BeforeAndAfter {
    
      final val actor = new StringActor
    
      before {
        actor ! Append("ScalaTest is ") // set up the fixture
      }
    
      after {
        actor ! Clear // clean up the fixture
      }
    
      "Testing" - {
        "should be easy" in {
          actor ! Append("easy!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is easy!")
          }
        }
    
        "should be fun" in {
          actor ! Append("fun!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is fun!")
          }
        }
      }
    }
    

    Note that the only way before and after code can communicate with test code is via some side-effecting mechanism, commonly by reassigning instance vars or by changing the state of mutable objects held from instance vals (as in this example). If using instance vars or mutable objects held from instance vals you wouldn't be able to run tests in parallel in the same instance of the test class (on the JVM, not Scala.js) unless you synchronized access to the shared, mutable state.

    Note that on the JVM, if you override ScalaTest's default serial execution context, you will likely need to worry about synchronizing access to shared mutable fixture state, because the execution context may assign different threads to process different Future transformations. Although access to mutable state along the same linear chain of Future transformations need not be synchronized, it can be difficult to spot cases where these constraints are violated. The best approach is to use only immutable objects when transforming Futures. When that's not practical, involve only thread-safe mutable objects, as is done in the above example. On Scala.js, by contrast, you need not worry about thread synchronization, because in effect only one thread exists.

    Although BeforeAndAfter provides a minimal-boilerplate way to execute code before and after tests, it isn't designed to enable stackable traits, because the order of execution would be non-obvious. If you want to factor out before and after code that is common to multiple test suites, you should use trait BeforeAndAfterEach instead, as shown later in the next section, composing fixtures by stacking traits.

    Composing fixtures by stacking traits

    In larger projects, teams often end up with several different fixtures that test classes need in different combinations, and possibly initialized (and cleaned up) in different orders. A good way to accomplish this in ScalaTest is to factor the individual fixtures into traits that can be composed using the stackable trait pattern. This can be done, for example, by placing withFixture methods in several traits, each of which call super.withFixture. Here's an example in which the StringBuilderActor and StringBufferActor fixtures used in the previous examples have been factored out into two stackable fixture traits named Builder and Buffer:

    package org.scalatest.examples.asyncfreespec.composingwithasyncfixture
    
    import org.scalatest._
    import org.scalatest.SuiteMixin
    import collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringBuilderActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class StringBufferActor {
      private final val buf = ListBuffer.empty[String]
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => buf += value
            case Clear => buf.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[List[String]] =
        Future {
          synchronized { buf.toList }
        }
    }
    
    trait Builder extends AsyncTestSuiteMixin { this: AsyncTestSuite =>
    
      final val builderActor = new StringBuilderActor
    
      abstract override def withFixture(test: NoArgAsyncTest) = {
        builderActor ! Append("ScalaTest is ")
        complete {
          super.withFixture(test) // To be stackable, must call super.withFixture
        } lastly {
          builderActor ! Clear
        }
      }
    }
    
    trait Buffer extends AsyncTestSuiteMixin { this: AsyncTestSuite =>
    
      final val bufferActor = new StringBufferActor
    
      abstract override def withFixture(test: NoArgAsyncTest) = {
        complete {
          super.withFixture(test) // To be stackable, must call super.withFixture
        } lastly {
          bufferActor ! Clear
        }
      }
    }
    
    class ExampleSpec extends AsyncFreeSpec with Builder with Buffer {
    
      "Testing" - {
        "should be easy" in {
          builderActor ! Append("easy!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is easy!")
            assert(lst.isEmpty)
            bufferActor ! Append("sweet")
            succeed
          }
        }
    
        "should be fun" in {
          builderActor ! Append("fun!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is fun!")
            assert(lst.isEmpty)
            bufferActor ! Append("awesome")
            succeed
          }
        }
      }
    }
    

    By mixing in both the Builder and Buffer traits, ExampleSpec gets both fixtures, which will be initialized before each test and cleaned up after. The order the traits are mixed together determines the order of execution. In this case, Builder is “super” to Buffer. If you wanted Buffer to be “super” to Builder, you need only switch the order you mix them together, like this:

    class Example2Spec extends AsyncFreeSpec with Buffer with Builder
    

    If you only need one fixture you mix in only that trait:

    class Example3Spec extends AsyncFreeSpec with Builder
    

    Another way to create stackable fixture traits is by extending the BeforeAndAfterEach and/or BeforeAndAfterAll traits. BeforeAndAfterEach has 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). Similarly, BeforeAndAfterAll has a beforeAll method that will be run before all tests, and an afterAll method that will be run after all tests. Here's what the previously shown example would look like if it were rewritten to use the BeforeAndAfterEach methods instead of withFixture:

    package org.scalatest.examples.asyncfreespec.composingbeforeandaftereach
    
    import org.scalatest._
    import org.scalatest.BeforeAndAfterEach
    import collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringBuilderActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class StringBufferActor {
      private final val buf = ListBuffer.empty[String]
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => buf += value
            case Clear => buf.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[List[String]] =
        Future {
          synchronized { buf.toList }
        }
    }
    
    trait Builder extends BeforeAndAfterEach { this: Suite =>
    
      final val builderActor = new StringBuilderActor
    
      override def beforeEach() {
        builderActor ! 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 builderActor ! Clear
      }
    }
    
    trait Buffer extends BeforeAndAfterEach { this: Suite =>
    
      final val bufferActor = new StringBufferActor
    
      override def afterEach() {
        try super.afterEach() // To be stackable, must call super.afterEach
        finally bufferActor ! Clear
      }
    }
    
    class ExampleSpec extends AsyncFreeSpec with Builder with Buffer {
    
      "Testing" - {
    
        "should be easy" in {
          builderActor ! Append("easy!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is easy!")
            assert(lst.isEmpty)
            bufferActor ! Append("sweet")
            succeed
          }
        }
    
        "should be fun" in {
          builderActor ! Append("fun!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is fun!")
            assert(lst.isEmpty)
            bufferActor ! Append("awesome")
            succeed
          }
        }
      }
    }
    

    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 difference between stacking traits that extend BeforeAndAfterEach versus traits that implement withFixture is that setup and cleanup code happens before and after the test in BeforeAndAfterEach, but at the beginning and end of the test in withFixture. Thus if a withFixture method completes abruptly with an exception, it is considered a failed test. By contrast, if any of the beforeEach or afterEach methods of BeforeAndAfterEach complete abruptly, it is considered an aborted suite, which will result in a SuiteAborted event.

    Shared tests

    Sometimes you may want to run the same test code on different fixture objects. In other words, you may want to write tests that are "shared" by different fixture objects. To accomplish this in an AsyncFreeSpec, you first place shared tests in behavior functions. These behavior functions will be invoked during the construction phase of any AsyncFreeSpec that uses them, so that the tests they contain will be registered as tests in that AsyncFreeSpec. For example, given this StackActor class:

    package org.scalatest.examples.asyncfreespec.sharedtests
    
    import scala.collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Stack operations
    case class Push[T](value: T)
    sealed abstract class StackOp
    case object Pop extends StackOp
    case object Peek extends StackOp
    case object Size extends StackOp
    
    // Stack info
    case class StackInfo[T](top: Option[T], size: Int, max: Int) {
      require(size > 0, "size was less than zero")
      require(max >= size, "max was less than size")
      val isFull: Boolean = size == max
      val isEmpty: Boolean = size == 0
    }
    
    class StackActor[T](Max: Int, name: String) {
    
      private final val buf = new ListBuffer[T]
    
      def !(push: Push[T]): Unit =
        synchronized {
          if (buf.size != Max)
            buf.prepend(push.value)
          else
            throw new IllegalStateException("can't push onto a full stack")
        }
    
      def ?(op: StackOp)(implicit c: ExecutionContext): Future[StackInfo[T]] =
        synchronized {
          op match {
            case Pop =>
              Future {
                if (buf.size != 0)
                  StackInfo(Some(buf.remove(0)), buf.size, Max)
                else
                  throw new IllegalStateException("can't pop an empty stack")
              }
            case Peek =>
              Future {
                if (buf.size != 0)
                  StackInfo(Some(buf(0)), buf.size, Max)
                else
                  throw new IllegalStateException("can't peek an empty stack")
              }
            case Size =>
              Future { StackInfo(None, buf.size, Max) }
          }
        }
    
      override def toString: String = name
    }
    

    You may want to test the stack represented by the StackActor class in different states: empty, full, with one item, with one item less than capacity, etc. You may find you have several tests that make sense any time the stack is non-empty. Thus you'd ideally want to run those same tests for three stack fixture objects: a full stack, a stack with a one item, and a stack with one item less than capacity. With shared tests, you can factor these tests out into a behavior function, into which you pass the stack fixture to use when running the tests. So in your AsyncFreeSpec for StackActor, you'd invoke the behavior function three times, passing in each of the three stack fixtures so that the shared tests are run for all three fixtures.

    You can define a behavior function that encapsulates these shared tests inside the AsyncFreeSpec that uses them. If they are shared between different AsyncFreeSpecs, however, you could also define them in a separate trait that is mixed into each AsyncFreeSpec that uses them. For example, here the nonEmptyStackActor behavior function (in this case, a behavior method) is defined in a trait along with another method containing shared tests for non-full stacks:

    import org.scalatest.AsyncFreeSpec
    
    trait AsyncFreeSpecStackBehaviors { this: AsyncFreeSpec =>
    
      def nonEmptyStackActor(createNonEmptyStackActor: => StackActor[Int],
            lastItemAdded: Int, name: String): Unit = {
    
        ("return non-empty StackInfo when Size is fired at non-empty stack actor: " + name) in {
          val stackActor = createNonEmptyStackActor
          val futureStackInfo = stackActor ? Size
          futureStackInfo map { stackInfo =>
            assert(!stackInfo.isEmpty)
          }
        }
    
        ("return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: " + name) in {
          val stackActor = createNonEmptyStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePeek <- stackActor ? Size
              afterPeek <- stackActor ? Peek
            } yield (beforePeek, afterPeek)
          futurePair map { case (beforePeek, afterPeek) =>
            assert(afterPeek.top == Some(lastItemAdded))
            assert(afterPeek.size == beforePeek.size)
          }
        }
    
        ("return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: " + name) in {
          val stackActor = createNonEmptyStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePop <- stackActor ? Size
              afterPop <- stackActor ? Pop
            } yield (beforePop, afterPop)
          futurePair map { case (beforePop, afterPop) =>
            assert(afterPop.top == Some(lastItemAdded))
            assert(afterPop.size == beforePop.size - 1)
          }
        }
      }
    
      def nonFullStackActor(createNonFullStackActor: => StackActor[Int], name: String): Unit = {
    
        ("return non-full StackInfo when Size is fired at non-full stack actor: " + name) in {
          val stackActor = createNonFullStackActor
          val futureStackInfo = stackActor ? Size
          futureStackInfo map { stackInfo =>
            assert(!stackInfo.isFull)
          }
        }
    
        ("return before and after StackInfo that has existing size + 1 and new item as top when Push is fired at non-full stack actor: " + name) in {
          val stackActor = createNonFullStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePush <- stackActor ? Size
              afterPush <- { stackActor ! Push(7); stackActor ? Peek }
            } yield (beforePush, afterPush)
          futurePair map { case (beforePush, afterPush) =>
            assert(afterPush.top == Some(7))
            assert(afterPush.size == beforePush.size + 1)
          }
        }
      }
    }
    

    Given these behavior functions, you could invoke them directly, but AsyncFreeSpec offers a DSL for the purpose, which looks like this:

    behave like nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName)
    

    Here's an example:

    class StackSpec extends AsyncFreeSpec with AsyncFreeSpecStackBehaviors {
    
      val Max = 10
      val LastValuePushed = Max - 1
    
      // Stack fixture creation methods
      val emptyStackActorName = "empty stack actor"
      def emptyStackActor = new StackActor[Int](Max, emptyStackActorName )
    
      val fullStackActorName = "full stack actor"
      def fullStackActor = {
        val stackActor = new StackActor[Int](Max, fullStackActorName )
        for (i <- 0 until Max)
          stackActor ! Push(i)
        stackActor
      }
    
      val almostEmptyStackActorName = "almost empty stack actor"
      def almostEmptyStackActor = {
        val stackActor = new StackActor[Int](Max, almostEmptyStackActorName )
        stackActor ! Push(LastValuePushed)
        stackActor
      }
    
      val almostFullStackActorName = "almost full stack actor"
      def almostFullStackActor = {
        val stackActor = new StackActor[Int](Max, almostFullStackActorName)
        for (i <- 1 to LastValuePushed)
          stackActor ! Push(i)
        stackActor
      }
    
      "A Stack" - {
        "(when empty)" - {
          "should be empty" in {
            val stackActor = emptyStackActor
            val futureStackInfo = stackActor ? Size
            futureStackInfo map { stackInfo =>
              assert(stackInfo.isEmpty)
            }
          }
    
          "should complain on peek" in {
            recoverToSucceededIf[IllegalStateException] {
              emptyStackActor ? Peek
            }
          }
    
          "should complain on pop" in {
            recoverToSucceededIf[IllegalStateException] {
              emptyStackActor ? Pop
            }
          }
        }
    
        "(with one item)" - {
          "should" - {
            behave like nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName)
            behave like nonFullStackActor(almostEmptyStackActor, almostEmptyStackActorName)
          }
        }
    
        "(with one item less than capacity)" - {
          "should" - {
            behave like nonEmptyStackActor(almostFullStackActor, LastValuePushed, almostFullStackActorName)
            behave like nonFullStackActor(almostFullStackActor, almostFullStackActorName)
          }
        }
    
        "(full)" - {
    
          "should be full" in {
            val stackActor = fullStackActor
            val futureStackInfo = stackActor ? Size
            futureStackInfo map { stackInfo =>
              assert(stackInfo.isFull)
            }
          }
    
          "should" - {
            behave like nonEmptyStackActor(fullStackActor, LastValuePushed, fullStackActorName)
          }
    
          "should complain on a push" in {
            val stackActor = fullStackActor
            assertThrows[IllegalStateException] {
              stackActor ! Push(10)
            }
          }
        }
      }
    }
    

    If you load these classes into the Scala interpreter (with scalatest's JAR file on the class path), and execute it, you'll see:

    scala> org.scalatest.run(new StackSpec)
    StackSpec:
    A Stack
      (when empty)
      - should be empty
      - should complain on peek
      - should complain on pop
      (with one item)
        should
        - return non-empty StackInfo when Size is fired at non-empty stack actor: almost empty stack actor
        - return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost empty stack actor
        - return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost empty stack actor
        - return non-full StackInfo when Size is fired at non-full stack actor: almost empty stack actor
        - return before and after StackInfo that has existing size + 1 and new item as top when Push is fired at non-full stack actor: almost empty stack actor
      (with one item less than capacity)
        should
        - return non-empty StackInfo when Size is fired at non-empty stack actor: almost full stack actor
        - return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost full stack actor
        - return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost full stack actor
        - return non-full StackInfo when Size is fired at non-full stack actor: almost full stack actor
        - return before and after StackInfo that has existing size + 1 and new item as top when Push is fired at non-full stack actor: almost full stack actor
      (full)
      - should be full
        should
        - return non-empty StackInfo when Size is fired at non-empty stack actor: full stack actor
        - return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: full stack actor
        - return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: full stack actor
      - should complain on a push
    
    

    One thing to keep in mind when using shared tests is that in ScalaTest, each test in a suite must have a unique name. If you register the same tests repeatedly in the same suite, one problem you may encounter is an exception at runtime complaining that multiple tests are being registered with the same test name. Although in an AsyncFreeSpec, the - clause is a nesting construct analogous to AsyncFunSpec's describe clause, you many sometimes need to do a bit of extra work to ensure that the test names are unique. If a duplicate test name problem shows up in an AsyncFreeSpec, you'll need to pass in a prefix or suffix string to add to each test name. You can call toString on the shared fixture object, or pass this string the same way you pass any other data needed by the shared tests. This is the approach taken by the previous AsyncFreeSpecStackBehaviors example.

    Given this AsyncFreeSpecStackBehaviors trait, calling it with the almostEmptyStackActor fixture, like this:

    behave like nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName)
    

    yields test names:

    • A Stack (when non-empty) should return non-empty StackInfo when Size is fired at non-empty stack actor: almost empty stack actor
    • A Stack (when non-empty) should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost empty stack actor
    • A Stack (when non-empty) should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost empty stack actor

    Whereas calling it with the almostFullStackActor fixture, like this:

    behave like nonEmptyStackActor(almostFullStackActor, LastValuePushed, almostFullStackActorName)
    

    yields different test names:

    • A Stack (when non-empty) should return non-empty StackInfo when Size is fired at non-empty stack actor: almost full stack actor
    • A Stack (when non-empty) should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost full stack actor
    • A Stack (when non-empty) should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost full stack actor
  12. trait AsyncFreeSpecLike extends AsyncTestSuite with AsyncTestRegistration with Informing with Notifying with Alerting with Documenting

    Permalink

    Implementation trait for class AsyncFreeSpec, which facilitates a “behavior-driven” style of development (BDD), in which tests are nested inside text clauses denoted with the dash operator (-).

    Implementation trait for class AsyncFreeSpec, which facilitates a “behavior-driven” style of development (BDD), in which tests are nested inside text clauses denoted with the dash operator (-).

    AsyncFreeSpec 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 AsyncFreeSpec into some other class, you can use this trait instead, because class AsyncFreeSpec does nothing more than extend this trait and add a nice toString implementation.

    See the documentation of the class for a detailed overview of AsyncFreeSpec.

    Annotations
    @JSExportDescendentClasses( true ) @Finders()
  13. abstract class AsyncFunSpec extends AsyncFunSpecLike

    Permalink

    Enables testing of asynchronous code without blocking, using a style consistent with traditional FunSpec tests.

    Enables testing of asynchronous code without blocking, using a style consistent with traditional FunSpec tests.

    Recommended Usage: AsyncFunSpec is intended to enable users of FunSpec to write non-blocking asynchronous tests that are consistent with their traditional FunSpec tests. Note: AsyncFunSpec is intended for use in special situations where non-blocking asynchronous testing is needed, with class FunSpec used for general needs.

    Given a Future returned by the code you are testing, you need not block until the Future completes before performing assertions against its value. You can instead map those assertions onto the Future and return the resulting Future[Assertion] to ScalaTest. The test will complete asynchronously, when the Future[Assertion] completes.

    Here's an example AsyncFunSpec:

    package org.scalatest.examples.asyncfunspec
    
    import org.scalatest.AsyncFunSpec
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFunSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      describe("addSoon") {
        it("will eventually compute a sum of passed Ints") {
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      describe("addNow") {
        it("will immediately compute a sum of passed Ints") {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    An AsyncFunSpec contains describe clauses and tests. You define a describe clause with describe, and a test with either it or they. describe, it, and they are methods, defined in AsyncFunSpec, which will be invoked by the primary constructor of AddSpec. A describe clause names, or gives more information about, the subject (class or other entity) you are specifying and testing. In the previous example, "addSoon" and "addNow" are the subjects under specification and test. With each test you provide a string (the spec text) that specifies one bit of behavior of the subject, and a block of code that tests that behavior. You place the spec text between the parentheses, followed by the test code between curly braces. The test code will be wrapped up as a function passed as a by-name parameter to it (or they), which will register the test for later execution.

    Note: the they method is intended for use when the subject is plural, for example:

    describe("The combinators") {
      they("should be easy to learn") { succeed }
      they("should be efficient") { succeed }
      they("should do something cool") { succeed }
    }
    

    Starting with version 3.0.0, ScalaTest assertions and matchers have result type Assertion. The result type of the first test in the example above, therefore, is Future[Assertion]. For clarity, here's the relevant code in a REPL session:

    scala> import org.scalatest._
    import org.scalatest._
    
    scala> import Assertions._
    import Assertions._
    
    scala> import scala.concurrent.Future
    import scala.concurrent.Future
    
    scala> import scala.concurrent.ExecutionContext
    import scala.concurrent.ExecutionContext
    
    scala> implicit val executionContext = ExecutionContext.Implicits.global
    executionContext: scala.concurrent.ExecutionContextExecutor = [email protected]
    
    scala> def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    addSoon: (addends: Int*)scala.concurrent.Future[Int]
    
    scala> val futureSum: Future[Int] = addSoon(1, 2)
    futureSum: scala.concurrent.Future[Int] = [email protected]
    
    scala> futureSum map { sum => assert(sum == 3) }
    res0: scala.concurrent.Future[org.scalatest.Assertion] = [email protected]
    

    The second test has result type Assertion:

    scala> def addNow(addends: Int*): Int = addends.sum
    addNow: (addends: Int*)Int
    
    scala> val sum: Int = addNow(1, 2)
    sum: Int = 3
    
    scala> assert(sum == 3)
    res1: org.scalatest.Assertion = Succeeded
    

    When AddSpec is constructed, the second test will be implicitly converted to Future[Assertion] and registered. The implicit conversion is from Assertion to Future[Assertion], so you must end synchronous tests in some ScalaTest assertion or matcher expression. If a test would not otherwise end in type Assertion, you can place succeed at the end of the test. succeed, a field in trait Assertions, returns the Succeeded singleton:

    scala> succeed
    res2: org.scalatest.Assertion = Succeeded
    

    Thus placing succeed at the end of a test body will satisfy the type checker:

      it("will immediately compute a sum of passed Ints") {
        val sum: Int = addNow(1, 2)
        assert(sum == 3)
        println("hi") // println has result type Unit
        succeed       // succeed has result type Assertion
      }
    

    An AsyncFunSpec's lifecycle has two phases: the registration phase and the ready phase. It starts in registration phase and enters ready phase the first time run is called on it. It then remains in ready phase for the remainder of its lifetime.

    Tests can only be registered with the it method while the AsyncFunSpec is in its registration phase. Any attempt to register a test after the AsyncFunSpec has entered its ready phase, i.e., after run has been invoked on the AsyncFunSpec, will be met with a thrown TestRegistrationClosedException. The recommended style of using AsyncFunSpec is to register tests during object construction as is done in all the examples shown here. If you keep to the recommended style, you should never see a TestRegistrationClosedException.

    Asynchronous execution model

    AsyncFunSpec extends AsyncTestSuite, which provides an implicit scala.concurrent.ExecutionContext named executionContext. This execution context is used by AsyncFunSpec to transform the Future[Assertion]s returned by each test into the FutureOutcome returned by the test function passed to withFixture. This ExecutionContext is also intended to be used in the tests, including when you map assertions onto futures.

    On both the JVM and Scala.js, the default execution context provided by ScalaTest's asynchronous testing styles confines execution to a single thread per test. On JavaScript, where single-threaded execution is the only possibility, the default execution context is scala.scalajs.concurrent.JSExecutionContext.Implicits.queue. On the JVM, the default execution context is a serial execution context provided by ScalaTest itself.

    When ScalaTest's serial execution context is called upon to execute a task, that task is recorded in a queue for later execution. For example, one task that will be placed in this queue is the task that transforms the Future[Assertion] returned by an asynchronous test body to the FutureOutcome returned from the test function. Other tasks that will be queued are any transformations of, or callbacks registered on, Futures that occur in your test body, including any assertions you map onto Futures. Once the test body returns, the thread that executed the test body will execute the tasks in that queue one after another, in the order they were enqueued.

    ScalaTest provides its serial execution context as the default on the JVM for three reasons. First, most often running both tests and suites in parallel does not give a significant performance boost compared to just running suites in parallel. Thus parallel execution of Future transformations within individual tests is not generally needed for performance reasons.

    Second, if multiple threads are operating in the same suite concurrently, you'll need to make sure access to any mutable fixture objects by multiple threads is synchronized. Although access to mutable state along the same linear chain of Future transformations need not be synchronized, this does not hold true for callbacks, and in general it is easy to make a mistake. Simply put: synchronizing access to shared mutable state is difficult and error prone. Because ScalaTest's default execution context on the JVM confines execution of Future transformations and call backs to a single thread, you need not (by default) worry about synchronizing access to mutable state in your asynchronous-style tests.

    Third, asynchronous-style tests need not be complete when the test body returns, because the test body returns a Future[Assertion]. This Future[Assertion] will often represent a test that has not yet completed. As a result, when using a more traditional execution context backed by a thread-pool, you could potentially start many more tests executing concurrently than there are threads in the thread pool. The more concurrently execute tests you have competing for threads from the same limited thread pool, the more likely it will be that tests will intermitently fail due to timeouts.

    Using ScalaTest's serial execution context on the JVM will ensure the same thread that produced the Future[Assertion] returned from a test body is also used to execute any tasks given to the execution context while executing the test body—and that thread will not be allowed to do anything else until the test completes. If the serial execution context's task queue ever becomes empty while the Future[Assertion] returned by that test's body has not yet completed, the thread will block until another task for that test is enqueued. Although it may seem counter-intuitive, this blocking behavior means the total number of tests allowed to run concurrently will be limited to the total number of threads executing suites. This fact means you can tune the thread pool such that maximum performance is reached while avoiding (or at least, reducing the likelihood of) tests that fail due to timeouts because of thread competition.

    This thread confinement strategy does mean, however, that when you are using the default execution context on the JVM, you must be sure to never block in the test body waiting for a task to be completed by the execution context. If you block, your test will never complete. This kind of problem will be obvious, because the test will consistently hang every time you run it. (If a test is hanging, and you're not sure which one it is, enable slowpoke notifications.) If you really do want to block in your tests, you may wish to just use a traditional FunSpec with ScalaFutures instead. Alternatively, you could override the executionContext and use a traditional ExecutionContext backed by a thread pool. This will enable you to block in an asynchronous-style test on the JVM, but you'll need to worry about synchronizing access to shared mutable state.

    To use a different execution context, just override executionContext. For example, if you prefer to use the runNow execution context on Scala.js instead of the default queue, you would write:

    // on Scala.js
    implicit override def executionContext =
        scala.scalajs.concurrent.JSExecutionContext.Implicits.runNow
    

    If you prefer on the JVM to use the global execution context, which is backed by a thread pool, instead of ScalaTest's default serial execution contex, which confines execution to a single thread, you would write:

    // on the JVM (and also compiles on Scala.js, giving
    // you the queue execution context)
    implicit override def executionContext =
        scala.concurrent.ExecutionContext.Implicits.global
    

    Serial and parallel test execution

    By default (unless you mix in ParallelTestExecution), tests in an AsyncFunSpec will be executed one after another, i.e., serially. This is true whether those tests return Assertion or Future[Assertion], no matter what threads are involved. This default behavior allows you to re-use a shared fixture, such as an external database that needs to be cleaned after each test, in multiple tests in async-style suites. This is implemented by registering each test, other than the first test, to run as a continuation after the previous test completes.

    If you want the tests of an AsyncFunSpec to be executed in parallel, you must mix in ParallelTestExecution and enable parallel execution of tests in your build. You enable parallel execution in Runner with the -P command line flag. In the ScalaTest Maven Plugin, set parallel to true. In sbt, parallel execution is the default, but to be explicit you can write:

    parallelExecution in Test := true // the default in sbt
    

    On the JVM, if both ParallelTestExecution is mixed in and parallel execution is enabled in the build, tests in an async-style suite will be started in parallel, using threads from the Distributor, and allowed to complete in parallel, using threads from the executionContext. If you are using ScalaTest's serial execution context, the JVM default, asynchronous tests will run in parallel very much like traditional (such as FunSpec) tests run in parallel: 1) Because ParallelTestExecution extends OneInstancePerTest, each test will run in its own instance of the test class, you need not worry about synchronizing access to mutable instance state shared by different tests in the same suite. 2) Because the serial execution context will confine the execution of each test to the single thread that executes the test body, you need not worry about synchronizing access to shared mutable state accessed by transformations and callbacks of Futures inside the test.

    If ParallelTestExecution is mixed in but parallel execution of suites is not enabled, asynchronous tests on the JVM will be started sequentially, by the single thread that invoked run, but without waiting for one test to complete before the next test is started. As a result, asynchronous tests will be allowed to complete in parallel, using threads from the executionContext. If you are using the serial execution context, however, you'll see the same behavior you see when parallel execution is disabled and a traditional suite that mixes in ParallelTestExecution is executed: the tests will run sequentially. If you use an execution context backed by a thread-pool, such as global, however, even though tests will be started sequentially by one thread, they will be allowed to run concurrently using threads from the execution context's thread pool.

    The latter behavior is essentially what you'll see on Scala.js when you execute a suite that mixes in ParallelTestExecution. Because only one thread exists when running under JavaScript, you can't "enable parallel execution of suites." However, it may still be useful to run tests in parallel on Scala.js, because tests can invoke API calls that are truly asynchronous by calling into external APIs that take advantage of non-JavaScript threads. Thus on Scala.js, ParallelTestExecution allows asynchronous tests to run in parallel, even though they must be started sequentially. This may give you better performance when you are using API calls in your Scala.js tests that are truly asynchronous.

    Futures and expected exceptions

    If you need to test for expected exceptions in the context of futures, you can use the recoverToSucceededIf and recoverToExceptionIf methods of trait RecoverMethods. Because this trait is mixed into supertrait AsyncTestSuite, both of these methods are available by default in an AsyncFunSpec.

    If you just want to ensure that a future fails with a particular exception type, and do not need to inspect the exception further, use recoverToSucceededIf:

    recoverToSucceededIf[IllegalStateException] { // Result type: Future[Assertion]
      emptyStackActor ? Peek
    }
    

    The recoverToSucceededIf method performs a job similar to assertThrows, except in the context of a future. It transforms a Future of any type into a Future[Assertion] that succeeds only if the original future fails with the specified exception. Here's an example in the REPL:

    scala> import org.scalatest.RecoverMethods._
    import org.scalatest.RecoverMethods._
    
    scala> import scala.concurrent.Future
    import scala.concurrent.Future
    
    scala> import scala.concurrent.ExecutionContext.Implicits.global
    import scala.concurrent.ExecutionContext.Implicits.global
    
    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { throw new IllegalStateException }
         | }
    res0: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res0.value
    res1: Option[scala.util.Try[org.scalatest.Assertion]] = Some(Success(Succeeded))
    

    Otherwise it fails with an error message similar to those given by assertThrows:

    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { throw new RuntimeException }
         | }
    res2: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res2.value
    res3: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: Expected exception
          java.lang.IllegalStateException to be thrown, but java.lang.RuntimeException
          was thrown))
    
    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { 42 }
         | }
    res4: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res4.value
    res5: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: Expected exception
          java.lang.IllegalStateException to be thrown, but no exception was thrown))
    

    The recoverToExceptionIf method differs from the recoverToSucceededIf in its behavior when the assertion succeeds: recoverToSucceededIf yields a Future[Assertion], whereas recoverToExceptionIf yields a Future[T], where T is the expected exception type.

    recoverToExceptionIf[IllegalStateException] { // Result type: Future[IllegalStateException]
      emptyStackActor ? Peek
    }
    

    In other words, recoverToExpectionIf is to intercept as recovertToSucceededIf is to assertThrows. The first one allows you to perform further assertions on the expected exception. The second one gives you a result type that will satisfy the type checker at the end of the test body. Here's an example showing recoverToExceptionIf in the REPL:

    scala> val futureEx =
         |   recoverToExceptionIf[IllegalStateException] {
         |     Future { throw new IllegalStateException("hello") }
         |   }
    futureEx: scala.concurrent.Future[IllegalStateException] = ...
    
    scala> futureEx.value
    res6: Option[scala.util.Try[IllegalStateException]] =
        Some(Success(java.lang.IllegalStateException: hello))
    
    scala> futureEx map { ex => assert(ex.getMessage == "world") }
    res7: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res7.value
    res8: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: "[hello]" did not equal "[world]"))
    

    Ignored tests

    To support the common use case of temporarily disabling a test, with the good intention of resurrecting the test at a later time, AsyncFunSpec provides registration methods that start with ignore instead of it or they. For example, to temporarily disable the test with the text "will eventually compute a sum of passed Ints", just change “it” into “ignore,” like this:

    package org.scalatest.examples.asyncfunspec.ignore
    
    import org.scalatest.AsyncFunSpec
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFunSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      describe("addSoon") {
        ignore("will eventually compute a sum of passed Ints") {
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      describe("addNow") {
        it("will immediately compute a sum of passed Ints") {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    If you run this version of AddSpec with:

    scala> org.scalatest.run(new AddSpec)
    

    It will run only the second test and report that the first test was ignored:

    AddSpec:
    addSoon
    - will eventually compute a sum of passed Ints !!! IGNORED !!!
    addNow
    - will immediately compute a sum of passed Ints
    

    If you wish to temporarily ignore an entire suite of tests, you can (on the JVM, not Scala.js) annotate the test class with @Ignore, like this:

    package org.scalatest.examples.asyncfunspec.ignoreall
    
    import org.scalatest.AsyncFunSpec
    import scala.concurrent.Future
    import org.scalatest.Ignore
    
    @Ignore
    class AddSpec extends AsyncFunSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      describe("addSoon") {
        it("will eventually compute a sum of passed Ints") {
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      describe("addNow") {
        it("will immediately compute a sum of passed Ints") {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    When you mark a test class with a tag annotation, ScalaTest will mark each test defined in that class with that tag. Thus, marking the AddSpec in the above example with the @Ignore tag annotation means that both tests in the class will be ignored. If you run the above AddSpec in the Scala interpreter, you'll see:

    AddSpec:
    addSoon
    - will eventually compute a sum of passed Ints !!! IGNORED !!!
    addNow
    - will immediately compute a sum of passed Ints !!! IGNORED !!!
    

    Note that marking a test class as ignored won't prevent it from being discovered by ScalaTest. Ignored classes will be discovered and run, and all their tests will be reported as ignored. This is intended to keep the ignored class visible, to encourage the developers to eventually fix and “un-ignore” it. If you want to prevent a class from being discovered at all (on the JVM, not Scala.js), use the DoNotDiscover annotation instead.

    If you want to ignore all tests of a suite on Scala.js, where annotations can't be inspected at runtime, you'll need to change it to ignore at each test site. To make a suite non-discoverable on Scala.js, ensure it does not declare a public no-arg constructor. You can either declare a public constructor that takes one or more arguments, or make the no-arg constructor non-public. Because this technique will also make the suite non-discoverable on the JVM, it is a good approach for suites you want to run (but not be discoverable) on both Scala.js and the JVM.

    Informers

    One of the parameters to AsyncFunSpec's run method is a Reporter, which will collect and report information about the running suite of tests. Information about suites and tests that were run, whether tests succeeded or failed, and tests that were ignored will be passed to the Reporter as the suite runs. Most often the reporting done by default by AsyncFunSpec's methods will be sufficient, but occasionally you may wish to provide custom information to the Reporter from a test. For this purpose, an Informer that will forward information to the current Reporter is provided via the info parameterless method. You can pass the extra information to the Informer via one of its apply methods. The Informer will then pass the information to the Reporter via an InfoProvided event. Here's an example in which the Informer returned by info is used implicitly by the Given, When, and Then methods of trait GivenWhenThen:

    package org.scalatest.examples.asyncfunspec.info
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends AsyncFunSpec with GivenWhenThen {
    
      describe("A mutable Set") {
        it("should allow an element to be added") {
          Given("an empty mutable Set")
          val set = mutable.Set.empty[String]
    
          When("an element is added")
          set += "clarity"
    
          Then("the Set should have size 1")
          assert(set.size === 1)
    
          And("the Set should contain the added element")
          assert(set.contains("clarity"))
    
          info("That's all folks!")
          succeed
        }
      }
    }
    

    If you run this AsyncFunSpec from the interpreter, you will see the following output:

    scala> org.scalatest.run(new SetSpec)
    A mutable Set
    - should allow an element to be added
      + Given an empty mutable Set
      + When an element is added
      + Then the Set should have size 1
      + And the Set should contain the added element
      + That's all folks! 
    

    Documenters

    AsyncFunSpec also provides a markup method that returns a Documenter, which allows you to send to the Reporter text formatted in Markdown syntax. You can pass the extra information to the Documenter via its apply method. The Documenter will then pass the information to the Reporter via an MarkupProvided event.

    Here's an example AsyncFunSpec that uses markup:

    package org.scalatest.examples.asyncfunspec.markup
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends AsyncFunSpec with GivenWhenThen {
    
      markup { """
    
    Mutable Set
    -----------
    
    A set is a collection that contains no duplicate elements.
    
    To implement a concrete mutable set, you need to provide implementations
    of the following methods:
    
        def contains(elem: A): Boolean
        def iterator: Iterator[A]
        def += (elem: A): this.type
        def -= (elem: A): this.type
    
    If you wish that methods like `take`,
    `drop`, `filter` return the same kind of set,
    you should also override:
    
        def empty: This
    
    It is also good idea to override methods `foreach` and
    `size` for efficiency.
    
      """ }
    
      describe("A mutable Set") {
        it("should allow an element to be added") {
          Given("an empty mutable Set")
          val set = mutable.Set.empty[String]
    
          When("an element is added")
          set += "clarity"
    
          Then("the Set should have size 1")
          assert(set.size === 1)
    
          And("the Set should contain the added element")
          assert(set.contains("clarity"))
    
          markup("This test finished with a **bold** statement!")
          succeed
        }
      }
    }
    

    Although all of ScalaTest's built-in reporters will display the markup text in some form, the HTML reporter will format the markup information into HTML. Thus, the main purpose of markup is to add nicely formatted text to HTML reports. Here's what the above SetSpec would look like in the HTML reporter:

    Notifiers and alerters

    ScalaTest records text passed to info and markup during tests, and sends the recorded text in the recordedEvents field of test completion events like TestSucceeded and TestFailed. This allows string reporters (like the standard out reporter) to show info and markup text after the test name in a color determined by the outcome of the test. For example, if the test fails, string reporters will show the info and markup text in red. If a test succeeds, string reporters will show the info and markup text in green. While this approach helps the readability of reports, it means that you can't use info to get status updates from long running tests.

    To get immediate (i.e., non-recorded) notifications from tests, you can use note (a Notifier) and alert (an Alerter). Here's an example showing the differences:

    package org.scalatest.examples.asyncfunspec.note
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends AsyncFunSpec {
    
      describe("A mutable Set") {
        it("should allow an element to be added") {
    
          info("info is recorded")
          markup("markup is *also* recorded")
          note("notes are sent immediately")
          alert("alerts are also sent immediately")
    
          val set = mutable.Set.empty[String]
          set += "clarity"
          assert(set.size === 1)
          assert(set.contains("clarity"))
        }
      }
    }
    

    Because note and alert information is sent immediately, it will appear before the test name in string reporters, and its color will be unrelated to the ultimate outcome of the test: note text will always appear in green, alert text will always appear in yellow. Here's an example:

    scala> org.scalatest.run(new SetSpec)
    SetSpec:
    A mutable Set
      + notes are sent immediately
      + alerts are also sent immediately
    - should allow an element to be added
      + info is recorded
      + markup is *also* recorded
    

    Another example is slowpoke notifications. If you find a test is taking a long time to complete, but you're not sure which test, you can enable slowpoke notifications. ScalaTest will use an Alerter to fire an event whenever a test has been running longer than a specified amount of time.

    In summary, use info and markup for text that should form part of the specification output. Use note and alert to send status notifications. (Because the HTML reporter is intended to produce a readable, printable specification, info and markup text will appear in the HTML report, but note and alert text will not.)

    Pending tests

    A pending test is one that has been given a name but is not yet implemented. The purpose of pending tests is to facilitate a style of testing in which documentation of behavior is sketched out before tests are written to verify that behavior (and often, before the behavior of the system being tested is itself implemented). Such sketches form a kind of specification of what tests and functionality to implement later.

    To support this style of testing, a test can be given a name that specifies one bit of behavior required by the system being tested. At the end of the test, it can call method pending, which will cause it to complete abruptly with TestPendingException.

    Because tests in ScalaTest can be designated as pending with TestPendingException, both the test name and any information sent to the reporter when running the test can appear in the report of a test run. (In other words, the code of a pending test is executed just like any other test.) However, because the test completes abruptly with TestPendingException, the test will be reported as pending, to indicate the actual test, and possibly the functionality, has not yet been implemented. Here's an example:

    package org.scalatest.examples.asyncfunspec.pending
    
    import org.scalatest.AsyncFunSpec
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFunSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      describe("addSoon") {
        it("will eventually compute a sum of passed Ints")(pending)
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      describe("addNow") {
        it("will immediately compute a sum of passed Ints") {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    (Note: "(pending)" is the body of the test. Thus the test contains just one statement, an invocation of the pending method, which throws TestPendingException.) If you run this version of AddSpec with:

    scala> org.scalatest.run(new AddSpec)
    

    It will run both tests, but report that first test is pending. You'll see:

    AddSpec:
    addSoon
    - will eventually compute a sum of passed Ints (pending)
    addNow
    - will immediately compute a sum of passed Ints
    

    One difference between an ignored test and a pending one is that an ignored test is intended to be used during significant refactorings of the code under test, when tests break and you don't want to spend the time to fix all of them immediately. You can mark some of those broken tests as ignored temporarily, so that you can focus the red bar on just failing tests you actually want to fix immediately. Later you can go back and fix the ignored tests. In other words, by ignoring some failing tests temporarily, you can more easily notice failed tests that you actually want to fix. By contrast, a pending test is intended to be used before a test and/or the code under test is written. Pending indicates you've decided to write a test for a bit of behavior, but either you haven't written the test yet, or have only written part of it, or perhaps you've written the test but don't want to implement the behavior it tests until after you've implemented a different bit of behavior you realized you need first. Thus ignored tests are designed to facilitate refactoring of existing code whereas pending tests are designed to facilitate the creation of new code.

    One other difference between ignored and pending tests is that ignored tests are implemented as a test tag that is excluded by default. Thus an ignored test is never executed. By contrast, a pending test is implemented as a test that throws TestPendingException (which is what calling the pending method does). Thus the body of pending tests are executed up until they throw TestPendingException.

    Tagging tests

    An AsyncFunSpec's tests may be classified into groups by tagging them with string names. As with any suite, when executing an AsyncFunSpec, groups of tests can optionally be included and/or excluded. To tag an AsyncFunSpec's tests, you pass objects that extend class org.scalatest.Tag to methods that register tests. Class Tag takes one parameter, a string name. If you have created tag annotation interfaces as described in the Tag documentation, then you will probably want to use tag names on your test functions that match. To do so, simply pass the fully qualified names of the tag interfaces to the Tag constructor. For example, if you've defined a tag annotation interface with fully qualified name, com.mycompany.tags.DbTest, then you could create a matching tag for AsyncFunSpecs like this:

    package org.scalatest.examples.asyncfunspec.tagging
    
    import org.scalatest.Tag
    
    object DbTest extends Tag("com.mycompany.tags.DbTest")
    

    Given these definitions, you could place AsyncFunSpec tests into groups with tags like this:

    import org.scalatest.AsyncFunSpec
    import org.scalatest.tagobjects.Slow
    import scala.concurrent.Future
    
    class AddSpec extends AsyncFunSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      describe("addSoon") {
        it("will eventually compute a sum of passed Ints", Slow) {
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      describe("addNow") {
        it("will immediately compute a sum of passed Ints",
          Slow, DbTest) {
    
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    This code marks both tests with the org.scalatest.tags.Slow tag, and the second test with the com.mycompany.tags.DbTest tag.

    The run method takes a Filter, whose constructor takes an optional Set[String] called tagsToInclude and a Set[String] called tagsToExclude. If tagsToInclude is None, all tests will be run except those those belonging to tags listed in the tagsToExclude Set. If tagsToInclude is defined, only tests belonging to tags mentioned in the tagsToInclude set, and not mentioned in tagsToExclude, will be run.

    It is recommended, though not required, that you create a corresponding tag annotation when you create a Tag object. A tag annotation (on the JVM, not Scala.js) allows you to tag all the tests of an AsyncFunSpec in one stroke by annotating the class. For more information and examples, see the documentation for class Tag. On Scala.js, to tag all tests of a suite, you'll need to tag each test individually at the test site.

    Shared fixtures

    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.

    ScalaTest recommends three techniques to eliminate such code duplication in async styles:

    • Refactor using Scala
    • Override withFixture
    • Mix in a before-and-after trait

    Each technique is geared towards helping you reduce code duplication without introducing instance vars, shared mutable objects, or other dependencies between tests. Eliminating shared mutable state across tests will make your test code easier to reason about and eliminate the need to synchronize access to shared mutable state on the JVM.

    The following sections describe these techniques, including explaining the recommended usage for each. But first, here's a table summarizing the options:

    Refactor using Scala when different tests need different fixtures.
    get-fixture methods The extract method refactor helps you create a fresh instances of mutable fixture objects in each test that needs them, but doesn't help you clean them up when you're done.
    loan-fixture methods Factor out dupicate code with the loan pattern when different tests need different fixtures that must be cleaned up afterwards.
    Override withFixture when most or all tests need the same fixture.
    withFixture(NoArgAsyncTest) The recommended default approach when most or all tests need the same fixture treatment. This general technique allows you, for example, to perform side effects at the beginning and end of all or most tests, transform the outcome of tests, retry tests, make decisions based on test names, tags, or other test data. Use this technique unless:
    Different tests need different fixtures (refactor using Scala instead)
    An exception in fixture code should abort the suite, not fail the test (use a before-and-after trait instead)
    You have objects to pass into tests (override withFixture(OneArgAsyncTest) instead)
    withFixture(OneArgAsyncTest) Use when you want to pass the same fixture object or objects as a parameter into all or most tests.
    Mix in a before-and-after trait when you want an aborted suite, not a failed test, if the fixture code fails.
    BeforeAndAfter Use this boilerplate-buster when you need to perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.
    BeforeAndAfterEach Use when you want to stack traits that perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.

    Calling get-fixture methods

    If you need to create the same mutable fixture objects in multiple tests, and don't need to clean them up after using them, the simplest approach is to write one or more get-fixture methods. A get-fixture method returns a new instance of a needed fixture object (or a holder object containing multiple fixture objects) each time it is called. You can call a get-fixture method at the beginning of each test that needs the fixture, storing the returned object or objects in local variables. Here's an example:

    package org.scalatest.examples.asyncfunspec.getfixture
    
    import org.scalatest.AsyncFunSpec
    import scala.concurrent.Future
    
    class ExampleSpec extends AsyncFunSpec {
    
      def fixture: Future[String] = Future { "ScalaTest is " }
    
      describe("Testing") {
        it("should be easy") {
          val future = fixture
          val result = future map { s => s + "easy!" }
          result map { s =>
            assert(s == "ScalaTest is easy!")
          }
        }
    
        it("should be fun") {
          val future = fixture
          val result = future map { s => s + "fun!" }
          result map { s =>
            assert(s == "ScalaTest is fun!")
          }
        }
      }
    }
    

    If you need to configure fixture objects differently in different tests, you can pass configuration into the get-fixture method. For example, you could pass in an initial value for a fixture object as a parameter to the get-fixture method.

    Overriding withFixture(NoArgAsyncTest)

    Although the get-fixture method approach takes care of setting up a fixture at the beginning of each test, it doesn't address the problem of cleaning up a fixture at the end of the test. If you just need to perform a side-effect at the beginning or end of a test, and don't need to actually pass any fixture objects into the test, you can override withFixture(NoArgAsyncTest), a method defined in trait AsyncTestSuite, a supertrait of AsyncFunSpec.

    Trait AsyncFunSpec's runTest method passes a no-arg async test function to withFixture(NoArgAsyncTest). It is withFixture's responsibility to invoke that test function. The default implementation of withFixture simply invokes the function and returns the result, like this:

    // Default implementation in trait AsyncTestSuite
    protected def withFixture(test: NoArgAsyncTest): FutureOutcome = {
      test()
    }
    

    You can, therefore, override withFixture to perform setup before invoking the test function, and/or perform cleanup after the test completes. The recommended way to ensure cleanup is performed after a test completes is to use the complete-lastly syntax, defined in supertrait CompleteLastly. The complete-lastly syntax will ensure that cleanup will occur whether future-producing code completes abruptly by throwing an exception, or returns normally yielding a future. In the latter case, complete-lastly will register the cleanup code to execute asynchronously when the future completes.

    The withFixture method is designed to be stacked, and to enable this, you should always call the super implementation of withFixture, 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)”, like this:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      complete {
        super.withFixture(test) // Invoke the test function
      } lastly {
        // Perform cleanup here
      }
    }
    

    If you have no cleanup to perform, you can write withFixture like this instead:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      super.withFixture(test) // Invoke the test function
    }
    

    If you want to perform an action only for certain outcomes, you'll need to register code performing that action as a callback on the Future using one of Future's registration methods: onComplete, onSuccess, or onFailure. Note that if a test fails, that will be treated as a scala.util.Success(org.scalatest.Failed). So if you want to perform an action if a test fails, for example, you'd register the callback using onSuccess.

    Here's an example in which withFixture(NoArgAsyncTest) is used to take a snapshot of the working directory if a test fails, and send that information to the standard output stream:

    package org.scalatest.examples.asyncfunspec.noargasynctest
    
    import java.io.File
    import org.scalatest._
    import scala.concurrent.Future
    
    class ExampleSpec extends AsyncFunSpec {
    
      override def withFixture(test: NoArgAsyncTest) = {
    
        super.withFixture(test) onFailedThen { _ =>
          val currDir = new File(".")
          val fileNames = currDir.list()
          info("Dir snapshot: " + fileNames.mkString(", "))
        }
      }
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      describe("This test") {
        it("should succeed") {
          addSoon(1, 1) map { sum => assert(sum == 2) }
        }
    
      it("should fail") {
          addSoon(1, 1) map { sum => assert(sum == 3) }
        }
      }
    }
    

    Running this version of ExampleSpec in the interpreter in a directory with two files, hello.txt and world.txt would give the following output:

    scala> org.scalatest.run(new ExampleSpec)
    ExampleSpec:
    This test
    - should succeed
    - should fail *** FAILED ***
      2 did not equal 3 (:33)
    

    Note that the NoArgAsyncTest passed to withFixture, in addition to an apply method that executes the test, also includes the test name and the config map passed to runTest. Thus you can also use the test name and configuration objects in your withFixture implementation.

    Lastly, if you want to transform the outcome in some way in withFixture, you'll need to use either the map or transform methods of Future, like this:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      val futureOutcome = super.withFixture(test) // Invoke the test function
    
      futureOutcome change { outcome =>
        // transform the outcome into a new outcome here
      }
    }
    

    Note that a NoArgAsyncTest's apply method will return a scala.util.Failure only if the test completes abruptly with a "test-fatal" exception (such as OutOfMemoryError) that should cause the suite to abort rather than the test to fail. Thus usually you would use map to transform future outcomes, not transform, so that such test-fatal exceptions pass through unchanged. The suite will abort asynchronously with any exception returned from NoArgAsyncTest's apply method in a scala.util.Failure.

    Calling loan-fixture methods

    If you need to both pass a fixture object into a test and perform cleanup at the end of the test, you'll need to use the loan pattern. If different tests need different fixtures that require cleanup, you can implement the loan pattern directly by writing loan-fixture methods. A loan-fixture method takes a function whose body forms part or all of a test's code. It creates a fixture, passes it to the test code by invoking the function, then cleans up the fixture after the function returns.

    The following example shows three tests that use two fixtures, a database and a file. Both require cleanup after, so each is provided via a loan-fixture method. (In this example, the database is simulated with a StringBuffer.)

    package org.scalatest.examples.asyncfunspec.loanfixture
    
    import java.util.concurrent.ConcurrentHashMap
    
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    object DbServer { // Simulating a database server
      type Db = StringBuffer
      private final val databases = new ConcurrentHashMap[String, Db]
      def createDb(name: String): Db = {
        val db = new StringBuffer // java.lang.StringBuffer is thread-safe
        databases.put(name, db)
        db
      }
      def removeDb(name: String): Unit = {
        databases.remove(name)
      }
    }
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    import org.scalatest._
    import DbServer._
    import java.util.UUID.randomUUID
    
    class ExampleSpec extends AsyncFunSpec {
    
      def withDatabase(testCode: Future[Db] => Future[Assertion]) = {
        val dbName = randomUUID.toString // generate a unique db name
        val futureDb = Future { createDb(dbName) } // create the fixture
        complete {
          val futurePopulatedDb =
            futureDb map { db =>
              db.append("ScalaTest is ") // perform setup
            }
          testCode(futurePopulatedDb) // "loan" the fixture to the test code
        } lastly {
          removeDb(dbName) // ensure the fixture will be cleaned up
        }
      }
    
      def withActor(testCode: StringActor => Future[Assertion]) = {
        val actor = new StringActor
        complete {
          actor ! Append("ScalaTest is ") // set up the fixture
          testCode(actor) // "loan" the fixture to the test code
        } lastly {
          actor ! Clear // ensure the fixture will be cleaned up
        }
      }
    
      describe("Testing") {
        // This test needs the actor fixture
        it("should be productive") {
          withActor { actor =>
            actor ! Append("productive!")
            val futureString = actor ? GetValue
            futureString map { s =>
              assert(s == "ScalaTest is productive!")
            }
          }
        }
      }
    
    describe("Test code") {
        // This test needs the database fixture
        it("should be readable") {
          withDatabase { futureDb =>
            futureDb map { db =>
              db.append("readable!")
              assert(db.toString == "ScalaTest is readable!")
            }
          }
        }
    
    // This test needs both the actor and the database
        it("should be clear and concise") {
          withDatabase { futureDb =>
            withActor { actor => // loan-fixture methods compose
              actor ! Append("concise!")
              val futureString = actor ? GetValue
              val futurePair: Future[(Db, String)] =
                futureDb zip futureString
              futurePair map { case (db, s) =>
                db.append("clear!")
                assert(db.toString == "ScalaTest is clear!")
                assert(s == "ScalaTest is concise!")
              }
            }
          }
        }
      }
    }
    

    As demonstrated by the last test, loan-fixture methods compose. Not only do loan-fixture methods allow you to give each test the fixture it needs, they allow you to give a test multiple fixtures and clean everything up afterwards.

    Also demonstrated in this example is the technique of giving each test its own "fixture sandbox" to play in. When your fixtures involve external side-effects, like creating databases, it is a good idea to give each database a unique name as is done in this example. This keeps tests completely isolated, allowing you to run them in parallel if desired.

    Overriding withFixture(OneArgTest)

    If all or most tests need the same fixture, you can avoid some of the boilerplate of the loan-fixture method approach by using a fixture.AsyncTestSuite and overriding withFixture(OneArgAsyncTest). Each test in a fixture.AsyncTestSuite takes a fixture as a parameter, allowing you to pass the fixture into the test. You must indicate the type of the fixture parameter by specifying FixtureParam, and implement a withFixture method that takes a OneArgAsyncTest. This withFixture method is responsible for invoking the one-arg async test function, so you can perform fixture set up before invoking and passing the fixture into the test function, and ensure clean up is performed after the test completes.

    To enable the stacking of traits that define withFixture(NoArgAsyncTest), it is a good idea to let withFixture(NoArgAsyncTest) invoke the test function instead of invoking the test function directly. To do so, you'll need to convert the OneArgAsyncTest to a NoArgAsyncTest. You can do that by passing the fixture object to the toNoArgAsyncTest method of OneArgAsyncTest. In other words, instead of writing “test(theFixture)”, you'd delegate responsibility for invoking the test function to the withFixture(NoArgAsyncTest) method of the same instance by writing:

    withFixture(test.toNoArgAsyncTest(theFixture))
    

    Here's a complete example:

    package org.scalatest.examples.asyncfunspec.oneargasynctest
    
    import org.scalatest._
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class ExampleSpec extends fixture.AsyncFunSpec {
    
      type FixtureParam = StringActor
    
      def withFixture(test: OneArgAsyncTest): FutureOutcome = {
    
      val actor = new StringActor
        complete {
          actor ! Append("ScalaTest is ") // set up the fixture
          withFixture(test.toNoArgAsyncTest(actor))
        } lastly {
          actor ! Clear // ensure the fixture will be cleaned up
        }
      }
    
      describe("Testing") {
        it("should be easy") { actor =>
          actor ! Append("easy!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is easy!")
          }
        }
    
        it("should be fun") { actor =>
          actor ! Append("fun!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is fun!")
          }
        }
      }
    }
    

    In this example, the tests required one fixture object, a StringActor. If your tests need multiple fixture objects, you can simply define the FixtureParam type to be a tuple containing the objects or, alternatively, a case class containing the objects. For more information on the withFixture(OneArgAsyncTest) technique, see the documentation for fixture.AsyncFunSpec.

    Mixing in BeforeAndAfter

    In all the shared fixture examples shown so far, the activities of creating, setting up, and cleaning up the fixture objects have been performed during the test. This means that if an exception occurs during any of these activities, it will be reported as a test failure. Sometimes, however, you may want setup to happen before the test starts, and cleanup after the test has completed, so that if an exception occurs during setup or cleanup, the entire suite aborts and no more tests are attempted. The simplest way to accomplish this in ScalaTest is to mix in trait BeforeAndAfter. With this trait you can denote a bit of code to run before each test with before and/or after each test each test with after, like this:

    package org.scalatest.examples.asyncfunspec.beforeandafter
    
    import org.scalatest.AsyncFunSpec
    import org.scalatest.BeforeAndAfter
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class ExampleSpec extends AsyncFunSpec with BeforeAndAfter {
    
      final val actor = new StringActor
    
      before {
        actor ! Append("ScalaTest is ") // set up the fixture
      }
    
      after {
        actor ! Clear // clean up the fixture
      }
    
      describe("Testing") {
        it("should be easy") {
          actor ! Append("easy!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is easy!")
          }
        }
    
        it("should be fun") {
          actor ! Append("fun!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is fun!")
          }
        }
      }
    }
    

    Note that the only way before and after code can communicate with test code is via some side-effecting mechanism, commonly by reassigning instance vars or by changing the state of mutable objects held from instance vals (as in this example). If using instance vars or mutable objects held from instance vals you wouldn't be able to run tests in parallel in the same instance of the test class (on the JVM, not Scala.js) unless you synchronized access to the shared, mutable state.

    Note that on the JVM, if you override ScalaTest's default serial execution context, you will likely need to worry about synchronizing access to shared mutable fixture state, because the execution context may assign different threads to process different Future transformations. Although access to mutable state along the same linear chain of Future transformations need not be synchronized, it can be difficult to spot cases where these constraints are violated. The best approach is to use only immutable objects when transforming Futures. When that's not practical, involve only thread-safe mutable objects, as is done in the above example. On Scala.js, by contrast, you need not worry about thread synchronization, because in effect only one thread exists.

    Although BeforeAndAfter provides a minimal-boilerplate way to execute code before and after tests, it isn't designed to enable stackable traits, because the order of execution would be non-obvious. If you want to factor out before and after code that is common to multiple test suites, you should use trait BeforeAndAfterEach instead, as shown later in the next section, composing fixtures by stacking traits.

    Composing fixtures by stacking traits

    In larger projects, teams often end up with several different fixtures that test classes need in different combinations, and possibly initialized (and cleaned up) in different orders. A good way to accomplish this in ScalaTest is to factor the individual fixtures into traits that can be composed using the stackable trait pattern. This can be done, for example, by placing withFixture methods in several traits, each of which call super.withFixture. Here's an example in which the StringBuilderActor and StringBufferActor fixtures used in the previous examples have been factored out into two stackable fixture traits named Builder and Buffer:

    package org.scalatest.examples.asyncfunspec.composingwithasyncfixture
    
    import org.scalatest._
    import org.scalatest.SuiteMixin
    import collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringBuilderActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class StringBufferActor {
      private final val buf = ListBuffer.empty[String]
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => buf += value
            case Clear => buf.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[List[String]] =
        Future {
          synchronized { buf.toList }
        }
    }
    
    trait Builder extends AsyncTestSuiteMixin { this: AsyncTestSuite =>
    
    final val builderActor = new StringBuilderActor
    
      abstract override def withFixture(test: NoArgAsyncTest) = {
        builderActor ! Append("ScalaTest is ")
        complete {
          super.withFixture(test) // To be stackable, must call super.withFixture
        } lastly {
          builderActor ! Clear
        }
      }
    }
    
    trait Buffer extends AsyncTestSuiteMixin { this: AsyncTestSuite =>
    
      final val bufferActor = new StringBufferActor
    
      abstract override def withFixture(test: NoArgAsyncTest) = {
        complete {
          super.withFixture(test) // To be stackable, must call super.withFixture
        } lastly {
          bufferActor ! Clear
        }
      }
    }
    
    class ExampleSpec extends AsyncFunSpec with Builder with Buffer {
    
      describe("Testing") {
        it("should be easy") {
          builderActor ! Append("easy!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is easy!")
            assert(lst.isEmpty)
            bufferActor ! Append("sweet")
            succeed
          }
        }
    
        it("should be fun") {
          builderActor ! Append("fun!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is fun!")
            assert(lst.isEmpty)
            bufferActor ! Append("awesome")
            succeed
          }
        }
      }
    }
    

    By mixing in both the Builder and Buffer traits, ExampleSpec gets both fixtures, which will be initialized before each test and cleaned up after. The order the traits are mixed together determines the order of execution. In this case, Builder is “super” to Buffer. If you wanted Buffer to be “super” to Builder, you need only switch the order you mix them together, like this:

    class Example2Spec extends AsyncFunSpec with Buffer with Builder
    

    If you only need one fixture you mix in only that trait:

    class Example3Spec extends AsyncFunSpec with Builder
    

    Another way to create stackable fixture traits is by extending the BeforeAndAfterEach and/or BeforeAndAfterAll traits. BeforeAndAfterEach has 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). Similarly, BeforeAndAfterAll has a beforeAll method that will be run before all tests, and an afterAll method that will be run after all tests. Here's what the previously shown example would look like if it were rewritten to use the BeforeAndAfterEach methods instead of withFixture:

    package org.scalatest.examples.asyncfunspec.composingbeforeandaftereach
    
    import org.scalatest._
    import org.scalatest.BeforeAndAfterEach
    import collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringBuilderActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class StringBufferActor {
      private final val buf = ListBuffer.empty[String]
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => buf += value
            case Clear => buf.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[List[String]] =
        Future {
          synchronized { buf.toList }
        }
    }
    
    trait Builder extends BeforeAndAfterEach { this: Suite =>
    
      final val builderActor = new StringBuilderActor
    
      override def beforeEach() {
        builderActor ! 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 builderActor ! Clear
      }
    }
    
    trait Buffer extends BeforeAndAfterEach { this: Suite =>
    
      final val bufferActor = new StringBufferActor
    
      override def afterEach() {
        try super.afterEach() // To be stackable, must call super.afterEach
        finally bufferActor ! Clear
      }
    }
    
    class ExampleSpec extends AsyncFunSpec with Builder with Buffer {
    
      describe("Testing") {
    
        it("should be easy") {
          builderActor ! Append("easy!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is easy!")
            assert(lst.isEmpty)
            bufferActor ! Append("sweet")
            succeed
          }
        }
    
        it("should be fun") {
          builderActor ! Append("fun!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is fun!")
            assert(lst.isEmpty)
            bufferActor ! Append("awesome")
            succeed
          }
        }
      }
    }
    

    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 difference between stacking traits that extend BeforeAndAfterEach versus traits that implement withFixture is that setup and cleanup code happens before and after the test in BeforeAndAfterEach, but at the beginning and end of the test in withFixture. Thus if a withFixture method completes abruptly with an exception, it is considered a failed test. By contrast, if any of the beforeEach or afterEach methods of BeforeAndAfterEach complete abruptly, it is considered an aborted suite, which will result in a SuiteAborted event.

    Shared tests

    Sometimes you may want to run the same test code on different fixture objects. In other words, you may want to write tests that are "shared" by different fixture objects. To accomplish this in an AsyncFunSpec, you first place shared tests in behavior functions. These behavior functions will be invoked during the construction phase of any AsyncFunSpec that uses them, so that the tests they contain will be registered as tests in that AsyncFunSpec. For example, given this StackActor class:

    package org.scalatest.examples.asyncfunspec.sharedtests
    
    import scala.collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Stack operations
    case class Push[T](value: T)
    sealed abstract class StackOp
    case object Pop extends StackOp
    case object Peek extends StackOp
    case object Size extends StackOp
    
    // Stack info
    case class StackInfo[T](top: Option[T], size: Int, max: Int) {
      require(size > 0, "size was less than zero")
      require(max > size, "max was less than size")
      val isFull: Boolean = size == max
      val isEmpty: Boolean = size == 0
    }
    
    class StackActor[T](Max: Int, name: String) {
    
      private final val buf = new ListBuffer[T]
    
      def !(push: Push[T]): Unit =
        synchronized {
          if (buf.size != Max)
            buf.prepend(push.value)
          else
            throw new IllegalStateException("can't push onto a full stack")
        }
    
      def ?(op: StackOp)(implicit c: ExecutionContext): Future[StackInfo[T]] =
        synchronized {
          op match {
            case Pop =>
              Future {
                if (buf.size != 0)
                  StackInfo(Some(buf.remove(0)), buf.size, Max)
                else
                  throw new IllegalStateException("can't pop an empty stack")
              }
            case Peek =>
              Future {
                if (buf.size != 0)
                  StackInfo(Some(buf(0)), buf.size, Max)
                else
                  throw new IllegalStateException("can't peek an empty stack")
              }
            case Size =>
              Future { StackInfo(None, buf.size, Max) }
          }
        }
    
      override def toString: String = name
    }
    

    You may want to test the stack represented by the StackActor class in different states: empty, full, with one item, with one item less than capacity, etc. You may find you have several tests that make sense any time the stack is non-empty. Thus you'd ideally want to run those same tests for three stack fixture objects: a full stack, a stack with a one item, and a stack with one item less than capacity. With shared tests, you can factor these tests out into a behavior function, into which you pass the stack fixture to use when running the tests. So in your AsyncFunSpec for StackActor, you'd invoke the behavior function three times, passing in each of the three stack fixtures so that the shared tests are run for all three fixtures.

    You can define a behavior function that encapsulates these shared tests inside the AsyncFunSpec that uses them. If they are shared between different AsyncFunSpecs, however, you could also define them in a separate trait that is mixed into each AsyncFunSpec that uses them. For example, here the nonEmptyStackActor behavior function (in this case, a behavior method) is defined in a trait along with another method containing shared tests for non-full stacks:

    import org.scalatest.AsyncFunSpec
    
    trait AsyncFunSpecStackBehaviors { this: AsyncFunSpec =>
    
      def nonEmptyStackActor(createNonEmptyStackActor: => StackActor[Int],
            lastItemAdded: Int, name: String): Unit = {
    
        it("should return non-empty StackInfo when Size is fired at non-empty stack actor: " + name) {
          val stackActor = createNonEmptyStackActor
          val futureStackInfo = stackActor ? Size
          futureStackInfo map { stackInfo =>
            assert(!stackInfo.isEmpty)
          }
        }
    
        it("should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: " + name) {
          val stackActor = createNonEmptyStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePeek <- stackActor ? Size
              afterPeek <- stackActor ? Peek
            } yield (beforePeek, afterPeek)
          futurePair map { case (beforePeek, afterPeek) =>
            assert(afterPeek.top == Some(lastItemAdded))
            assert(afterPeek.size == beforePeek.size)
          }
        }
    
        it("should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: " + name) {
          val stackActor = createNonEmptyStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePop <- stackActor ? Size
              afterPop <- stackActor ? Pop
            } yield (beforePop, afterPop)
          futurePair map { case (beforePop, afterPop) =>
            assert(afterPop.top == Some(lastItemAdded))
            assert(afterPop.size == beforePop.size - 1)
          }
        }
      }
    
      def nonFullStackActor(createNonFullStackActor: => StackActor[Int], name: String): Unit = {
    
        it("should return non-full StackInfo when Size is fired at non-full stack actor: " + name) {
          val stackActor = createNonFullStackActor
          val futureStackInfo = stackActor ? Size
          futureStackInfo map { stackInfo =>
            assert(!stackInfo.isFull)
          }
        }
    
        it("should return before and after StackInfo that has existing size + 1 and new item as top when Push is fired at non-full stack actor: " + name) {
          val stackActor = createNonFullStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePush <- stackActor ? Size
              afterPush <- { stackActor ! Push(7); stackActor ? Peek }
            } yield (beforePush, afterPush)
          futurePair map { case (beforePush, afterPush) =>
            assert(afterPush.top == Some(7))
            assert(afterPush.size == beforePush.size + 1)
          }
        }
      }
    }
    

    Given these behavior functions, you could invoke them directly, but AsyncFunSpec offers a DSL for the purpose, which looks like this:

    it should behave like nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName)
    it should behave like nonFullStackActor(almostEmptyStackActor, almostEmptyStackActorName)
    

    Here's an example:

    class StackSpec extends AsyncFunSpec with AsyncFunSpecStackBehaviors {
    
      val Max = 10
      val LastValuePushed = Max - 1
    
      // Stack fixture creation methods
      val emptyStackActorName = "empty stack actor"
      def emptyStackActor = new StackActor[Int](Max, emptyStackActorName )
    
      val fullStackActorName = "full stack actor"
      def fullStackActor = {
        val stackActor = new StackActor[Int](Max, fullStackActorName )
        for (i <- 0 until Max)
          stackActor ! Push(i)
        stackActor
      }
    
      val almostEmptyStackActorName = "almost empty stack actor"
      def almostEmptyStackActor = {
        val stackActor = new StackActor[Int](Max, almostEmptyStackActorName )
        stackActor ! Push(LastValuePushed)
        stackActor
      }
    
      val almostFullStackActorName = "almost full stack actor"
      def almostFullStackActor = {
        val stackActor = new StackActor[Int](Max, almostFullStackActorName)
        for (i <- 1 to LastValuePushed)
          stackActor ! Push(i)
        stackActor
      }
    
      describe("A Stack") {
        describe("(when empty)") {
          it("should be empty") {
            val stackActor = emptyStackActor
            val futureStackInfo = stackActor ? Size
            futureStackInfo map { stackInfo =>
              assert(stackInfo.isEmpty)
            }
          }
    
          it("should complain on peek") {
            recoverToSucceededIf[IllegalStateException] {
              emptyStackActor ? Peek
            }
          }
    
          it("should complain on pop") {
            recoverToSucceededIf[IllegalStateException] {
              emptyStackActor ? Pop
            }
          }
        }
    
        describe("(when non-empty)") {
          it should behave like nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName)
          it should behave like nonFullStackActor(almostEmptyStackActor, almostEmptyStackActorName)
          it should behave like nonEmptyStackActor(almostFullStackActor, LastValuePushed, almostFullStackActorName)
          it should behave like nonFullStackActor(almostFullStackActor, almostFullStackActorName)
        }
    
        describe("(when full)") {
    
          it("should be full") {
            val stackActor = fullStackActor
            val futureStackInfo = stackActor ? Size
            futureStackInfo map { stackInfo =>
              assert(stackInfo.isFull)
            }
          }
    
          it should behave like nonEmptyStackActor(fullStackActor, LastValuePushed, fullStackActorName)
    
          it("should complain on a push") {
            val stackActor = fullStackActor
            assertThrows[IllegalStateException] {
              stackActor ! Push(10)
            }
          }
        }
      }
    }
    

    If you load these classes into the Scala interpreter (with scalatest's JAR file on the class path), and execute it, you'll see:

    scala> org.scalatest.run(new StackSpec)
    StackSpec:
    A Stack
      (when empty)
      - should be empty
      - should complain on peek
      - should complain on pop
      (when non-empty)
      - should return non-empty StackInfo when Size is fired at non-empty stack actor: almost empty stack actor
      - should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost empty stack actor
      - should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost empty stack actor
      - should return non-full StackInfo when Size is fired at non-full stack actor: almost empty stack actor
      - should return before and after StackInfo that has existing size + 1 and new item as top when Push is fired at non-full stack actor: almost empty stack actor
      - should return non-empty StackInfo when Size is fired at non-empty stack actor: almost full stack actor
      - should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost full stack actor
      - should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost full stack actor
      - should return non-full StackInfo when Size is fired at non-full stack actor: almost full stack actor
      - should return before and after StackInfo that has existing size + 1 and new item as top when Push is fired at non-full stack actor: almost full stack actor
      (when full)
      - should be full
      - should return non-empty StackInfo when Size is fired at non-empty stack actor: full stack actor
      - should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: full stack actor
      - should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: full stack actor
      - should complain on a push
    
    

    One thing to keep in mind when using shared tests is that in ScalaTest, each test in a suite must have a unique name. If you register the same tests repeatedly in the same suite, one problem you may encounter is an exception at runtime complaining that multiple tests are being registered with the same test name. Therefore, you need to do a bit of extra work to ensure that the test names are unique. If a duplicate test name problem shows up in an AsyncFunSpec, you'll need to pass in a prefix or suffix string to add to each test name. You can call toString on the shared fixture object, or pass this string the same way you pass any other data needed by the shared tests. This is the approach taken by the previous AsyncFunSpecStackBehaviors example.

    Given this AsyncFunSpecStackBehaviors trait, calling it with the stackWithOneItem fixture, like this:

    it should behave like nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName)
    

    yields test names:

    • A Stack (when non-empty) should return non-empty StackInfo when Size is fired at non-empty stack actor: almost empty stack actor
    • A Stack (when non-empty) should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost empty stack actor
    • A Stack (when non-empty) should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost empty stack actor

    Whereas calling it with the stackWithOneItemLessThanCapacity fixture, like this:

    it should behave like nonEmptyStackActor(almostFullStackActor, LastValuePushed, almostFullStackActorName)
    

    yields different test names:

    • A Stack (when non-empty) should return non-empty StackInfo when Size is fired at non-empty stack actor: almost full stack actor
    • A Stack (when non-empty) should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost full stack actor
    • A Stack (when non-empty) should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost full stack actor
  14. trait AsyncFunSpecLike extends AsyncTestSuite with AsyncTestRegistration with Informing with Notifying with Alerting with Documenting

    Permalink

    Implementation trait for class AsyncFunSpec, which facilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.

    Implementation trait for class AsyncFunSpec, which facilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.

    AsyncFunSpec 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 AsyncFunSpec into some other class, you can use this trait instead, because class AsyncFunSpec does nothing more than extend this trait and add a nice toString implementation.

    See the documentation of the class for a detailed overview of AsyncFunSpec.

    Annotations
    @JSExportDescendentClasses( true ) @Finders()
  15. abstract class AsyncFunSuite extends AsyncFunSuiteLike

    Permalink

    Enables testing of asynchronous code without blocking, using a style consistent with traditional FunSuite tests.

    Enables testing of asynchronous code without blocking, using a style consistent with traditional FunSuite tests.

    Recommended Usage: AsyncFunSuite is intended to enable users of FunSuite to write non-blocking asynchronous tests that are consistent with their traditional FunSuite tests. Note: AsyncFunSuite is intended for use in special situations where non-blocking asynchronous testing is needed, with class FunSuite used for general needs.

    Given a Future returned by the code you are testing, you need not block until the Future completes before performing assertions against its value. You can instead map those assertions onto the Future and return the resulting Future[Assertion] to ScalaTest. The test will complete asynchronously, when the Future[Assertion] completes.

    Here's an example AsyncFunSuite:

    package org.scalatest.examples.asyncfunsuite
    
    import org.scalatest.AsyncFunSuite
    import scala.concurrent.Future
    
    class AddSuite extends AsyncFunSuite {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      test("addSoon will eventually compute a sum of passed Ints") {
        val futureSum: Future[Int] = addSoon(1, 2)
        // You can map assertions onto a Future, then return
        // the resulting Future[Assertion] to ScalaTest:
        futureSum map { sum => assert(sum == 3) }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      test("addNow will immediately compute a sum of passed Ints") {
        val sum: Int = addNow(1, 2)
        // You can also write synchronous tests, which
        // must result in type Assertion:
        assert(sum == 3)
      }
    }
    

    test” is a method, defined in AsyncFunSuite, which will be invoked by the primary constructor of AddSuite. You specify the name of the test as a string between the parentheses, and the test code itself between curly braces. The test code is a function passed as a by-name parameter to test, which registers it for later execution. The result type of the by-name in an AsyncFunSuite must be Future[Assertion].

    Starting with version 3.0.0, ScalaTest assertions and matchers have result type Assertion. The result type of the first test in the example above, therefore, is Future[Assertion]. For clarity, here's the relevant code in a REPL session:

    scala> import org.scalatest._
    import org.scalatest._
    
    scala> import Assertions._
    import Assertions._
    
    scala> import scala.concurrent.Future
    import scala.concurrent.Future
    
    scala> import scala.concurrent.ExecutionContext
    import scala.concurrent.ExecutionContext
    
    scala> implicit val executionContext = ExecutionContext.Implicits.global
    executionContext: scala.concurrent.ExecutionContextExecutor = [email protected]
    
    scala> def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    addSoon: (addends: Int*)scala.concurrent.Future[Int]
    
    scala> val futureSum: Future[Int] = addSoon(1, 2)
    futureSum: scala.concurrent.Future[Int] = [email protected]
    
    scala> futureSum map { sum => assert(sum == 3) }
    res0: scala.concurrent.Future[org.scalatest.Assertion] = [email protected]
    

    The second test has result type Assertion:

    scala> def addNow(addends: Int*): Int = addends.sum
    addNow: (addends: Int*)Int
    
    scala> val sum: Int = addNow(1, 2)
    sum: Int = 3
    
    scala> assert(sum == 3)
    res1: org.scalatest.Assertion = Succeeded
    

    When AddSuite is constructed, the second test will be implicitly converted to Future[Assertion] and registered. The implicit conversion is from Assertion to Future[Assertion], so you must end synchronous tests in some ScalaTest assertion or matcher expression. If a test would not otherwise end in type Assertion, you can place succeed at the end of the test. succeed, a field in trait Assertions, returns the Succeeded singleton:

    scala> succeed
    res2: org.scalatest.Assertion = Succeeded
    

    Thus placing succeed at the end of a test body will satisfy the type checker:

      test("addNow will immediately compute a sum of passed Ints") {
        val sum: Int = addNow(1, 2)
        assert(sum == 3)
        println("hi") // println has result type Unit
        succeed       // succeed has result type Assertion
      }
    

    An AsyncFunSuite's lifecycle has two phases: the registration phase and the ready phase. It starts in registration phase and enters ready phase the first time run is called on it. It then remains in ready phase for the remainder of its lifetime.

    Tests can only be registered with the test method while the AsyncFunSuite is in its registration phase. Any attempt to register a test after the AsyncFunSuite has entered its ready phase, i.e., after run has been invoked on the AsyncFunSuite, will be met with a thrown TestRegistrationClosedException. The recommended style of using AsyncFunSuite is to register tests during object construction as is done in all the examples shown here. If you keep to the recommended style, you should never see a TestRegistrationClosedException.

    Asynchronous execution model

    AsyncFunSuite extends AsyncTestSuite, which provides an implicit scala.concurrent.ExecutionContext named executionContext. This execution context is used by AsyncFunSuite to transform the Future[Assertion]s returned by each test into the FutureOutcome returned by the test function passed to withFixture. This ExecutionContext is also intended to be used in the tests, including when you map assertions onto futures.

    On both the JVM and Scala.js, the default execution context provided by ScalaTest's asynchronous testing styles confines execution to a single thread per test. On JavaScript, where single-threaded execution is the only possibility, the default execution context is scala.scalajs.concurrent.JSExecutionContext.Implicits.queue. On the JVM, the default execution context is a serial execution context provided by ScalaTest itself.

    When ScalaTest's serial execution context is called upon to execute a task, that task is recorded in a queue for later execution. For example, one task that will be placed in this queue is the task that transforms the Future[Assertion] returned by an asynchronous test body to the FutureOutcome returned from the test function. Other tasks that will be queued are any transformations of, or callbacks registered on, Futures that occur in your test body, including any assertions you map onto Futures. Once the test body returns, the thread that executed the test body will execute the tasks in that queue one after another, in the order they were enqueued.

    ScalaTest provides its serial execution context as the default on the JVM for three reasons. First, most often running both tests and suites in parallel does not give a significant performance boost compared to just running suites in parallel. Thus parallel execution of Future transformations within individual tests is not generally needed for performance reasons.

    Second, if multiple threads are operating in the same suite concurrently, you'll need to make sure access to any mutable fixture objects by multiple threads is synchronized. Although access to mutable state along the same linear chain of Future transformations need not be synchronized, this does not hold true for callbacks, and in general it is easy to make a mistake. Simply put: synchronizing access to shared mutable state is difficult and error prone. Because ScalaTest's default execution context on the JVM confines execution of Future transformations and call backs to a single thread, you need not (by default) worry about synchronizing access to mutable state in your asynchronous-style tests.

    Third, asynchronous-style tests need not be complete when the test body returns, because the test body returns a Future[Assertion]. This Future[Assertion] will often represent a test that has not yet completed. As a result, when using a more traditional execution context backed by a thread-pool, you could potentially start many more tests executing concurrently than there are threads in the thread pool. The more concurrently execute tests you have competing for threads from the same limited thread pool, the more likely it will be that tests will intermitently fail due to timeouts.

    Using ScalaTest's serial execution context on the JVM will ensure the same thread that produced the Future[Assertion] returned from a test body is also used to execute any tasks given to the execution context while executing the test body—and that thread will not be allowed to do anything else until the test completes. If the serial execution context's task queue ever becomes empty while the Future[Assertion] returned by that test's body has not yet completed, the thread will block until another task for that test is enqueued. Although it may seem counter-intuitive, this blocking behavior means the total number of tests allowed to run concurrently will be limited to the total number of threads executing suites. This fact means you can tune the thread pool such that maximum performance is reached while avoiding (or at least, reducing the likelihood of) tests that fail due to timeouts because of thread competition.

    This thread confinement strategy does mean, however, that when you are using the default execution context on the JVM, you must be sure to never block in the test body waiting for a task to be completed by the execution context. If you block, your test will never complete. This kind of problem will be obvious, because the test will consistently hang every time you run it. (If a test is hanging, and you're not sure which one it is, enable slowpoke notifications.) If you really do want to block in your tests, you may wish to just use a traditional FunSuite with ScalaFutures instead. Alternatively, you could override the executionContext and use a traditional ExecutionContext backed by a thread pool. This will enable you to block in an asynchronous-style test on the JVM, but you'll need to worry about synchronizing access to shared mutable state.

    To use a different execution context, just override executionContext. For example, if you prefer to use the runNow execution context on Scala.js instead of the default queue, you would write:

    // on Scala.js
    implicit override def executionContext =
        scala.scalajs.concurrent.JSExecutionContext.Implicits.runNow
    

    If you prefer on the JVM to use the global execution context, which is backed by a thread pool, instead of ScalaTest's default serial execution contex, which confines execution to a single thread, you would write:

    // on the JVM (and also compiles on Scala.js, giving
    // you the queue execution context)
    implicit override def executionContext =
        scala.concurrent.ExecutionContext.Implicits.global
    

    Serial and parallel test execution

    By default (unless you mix in ParallelTestExecution), tests in an AsyncFunSuite will be executed one after another, i.e., serially. This is true whether those tests return Assertion or Future[Assertion], no matter what threads are involved. This default behavior allows you to re-use a shared fixture, such as an external database that needs to be cleaned after each test, in multiple tests in async-style suites. This is implemented by registering each test, other than the first test, to run as a continuation after the previous test completes.

    If you want the tests of an AsyncFunSuite to be executed in parallel, you must mix in ParallelTestExecution and enable parallel execution of tests in your build. You enable parallel execution in Runner with the -P command line flag. In the ScalaTest Maven Plugin, set parallel to true. In sbt, parallel execution is the default, but to be explicit you can write:

    parallelExecution in Test := true // the default in sbt
    

    On the JVM, if both ParallelTestExecution is mixed in and parallel execution is enabled in the build, tests in an async-style suite will be started in parallel, using threads from the Distributor, and allowed to complete in parallel, using threads from the executionContext. If you are using ScalaTest's serial execution context, the JVM default, asynchronous tests will run in parallel very much like traditional (such as FunSuite) tests run in parallel: 1) Because ParallelTestExecution extends OneInstancePerTest, each test will run in its own instance of the test class, you need not worry about synchronizing access to mutable instance state shared by different tests in the same suite. 2) Because the serial execution context will confine the execution of each test to the single thread that executes the test body, you need not worry about synchronizing access to shared mutable state accessed by transformations and callbacks of Futures inside the test.

    If ParallelTestExecution is mixed in but parallel execution of suites is not enabled, asynchronous tests on the JVM will be started sequentially, by the single thread that invoked run, but without waiting for one test to complete before the next test is started. As a result, asynchronous tests will be allowed to complete in parallel, using threads from the executionContext. If you are using the serial execution context, however, you'll see the same behavior you see when parallel execution is disabled and a traditional suite that mixes in ParallelTestExecution is executed: the tests will run sequentially. If you use an execution context backed by a thread-pool, such as global, however, even though tests will be started sequentially by one thread, they will be allowed to run concurrently using threads from the execution context's thread pool.

    The latter behavior is essentially what you'll see on Scala.js when you execute a suite that mixes in ParallelTestExecution. Because only one thread exists when running under JavaScript, you can't "enable parallel execution of suites." However, it may still be useful to run tests in parallel on Scala.js, because tests can invoke API calls that are truly asynchronous by calling into external APIs that take advantage of non-JavaScript threads. Thus on Scala.js, ParallelTestExecution allows asynchronous tests to run in parallel, even though they must be started sequentially. This may give you better performance when you are using API calls in your Scala.js tests that are truly asynchronous.

    Futures and expected exceptions

    If you need to test for expected exceptions in the context of futures, you can use the recoverToSucceededIf and recoverToExceptionIf methods of trait RecoverMethods. Because this trait is mixed into supertrait AsyncTestSuite, both of these methods are available by default in an AsyncFunSuite.

    If you just want to ensure that a future fails with a particular exception type, and do not need to inspect the exception further, use recoverToSucceededIf:

    recoverToSucceededIf[IllegalStateException] { // Result type: Future[Assertion]
      emptyStackActor ? Peek
    }
    

    The recoverToSucceededIf method performs a job similar to assertThrows, except in the context of a future. It transforms a Future of any type into a Future[Assertion] that succeeds only if the original future fails with the specified exception. Here's an example in the REPL:

    scala> import org.scalatest.RecoverMethods._
    import org.scalatest.RecoverMethods._
    
    scala> import scala.concurrent.Future
    import scala.concurrent.Future
    
    scala> import scala.concurrent.ExecutionContext.Implicits.global
    import scala.concurrent.ExecutionContext.Implicits.global
    
    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { throw new IllegalStateException }
         | }
    res0: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res0.value
    res1: Option[scala.util.Try[org.scalatest.Assertion]] = Some(Success(Succeeded))
    

    Otherwise it fails with an error message similar to those given by assertThrows:

    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { throw new RuntimeException }
         | }
    res2: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res2.value
    res3: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: Expected exception
          java.lang.IllegalStateException to be thrown, but java.lang.RuntimeException
          was thrown))
    
    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { 42 }
         | }
    res4: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res4.value
    res5: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: Expected exception
          java.lang.IllegalStateException to be thrown, but no exception was thrown))
    

    The recoverToExceptionIf method differs from the recoverToSucceededIf in its behavior when the assertion succeeds: recoverToSucceededIf yields a Future[Assertion], whereas recoverToExceptionIf yields a Future[T], where T is the expected exception type.

    recoverToExceptionIf[IllegalStateException] { // Result type: Future[IllegalStateException]
      emptyStackActor ? Peek
    }
    

    In other words, recoverToExpectionIf is to intercept as recovertToSucceededIf is to assertThrows. The first one allows you to perform further assertions on the expected exception. The second one gives you a result type that will satisfy the type checker at the end of the test body. Here's an example showing recoverToExceptionIf in the REPL:

    scala> val futureEx =
         |   recoverToExceptionIf[IllegalStateException] {
         |     Future { throw new IllegalStateException("hello") }
         |   }
    futureEx: scala.concurrent.Future[IllegalStateException] = ...
    
    scala> futureEx.value
    res6: Option[scala.util.Try[IllegalStateException]] =
        Some(Success(java.lang.IllegalStateException: hello))
    
    scala> futureEx map { ex => assert(ex.getMessage == "world") }
    res7: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res7.value
    res8: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: "[hello]" did not equal "[world]"))
    

    Ignored tests

    To support the common use case of temporarily disabling a test, with the good intention of resurrecting the test at a later time, AsyncFunSuite provides registration methods that start with ignore instead of test. Here's an example:

    package org.scalatest.examples.asyncfunsuite.ignore
    
    import org.scalatest.AsyncFunSuite
    import scala.concurrent.Future
    
    class AddSuite extends AsyncFunSuite {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      ignore("addSoon will eventually compute a sum of passed Ints") {
        val futureSum: Future[Int] = addSoon(1, 2)
        // You can map assertions onto a Future, then return
        // the resulting Future[Assertion] to ScalaTest:
        futureSum map { sum => assert(sum == 3) }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      test("addNow will immediately compute a sum of passed Ints") {
        val sum: Int = addNow(1, 2)
        // You can also write synchronous tests. The body
        // must have result type Assertion:
        assert(sum == 3)
      }
    }
    

    If you run this version of AddSuite with:

    scala> org.scalatest.run(new AddSuite)
    

    It will run only the second test and report that the first test was ignored:

    AddSuite:
    - addSoon will eventually compute a sum of passed Ints !!! IGNORED !!!
    - addNow will immediately compute a sum of passed Ints
    

    If you wish to temporarily ignore an entire suite of tests, you can (on the JVM, not Scala.js) annotate the test class with @Ignore, like this:

    package org.scalatest.examples.asyncfunsuite.ignoreall
    
    import org.scalatest.AsyncFunSuite
    import scala.concurrent.Future
    import org.scalatest.Ignore
    
    @Ignore
    class AddSuite extends AsyncFunSuite {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      test("addSoon will eventually compute a sum of passed Ints") {
        val futureSum: Future[Int] = addSoon(1, 2)
        // You can map assertions onto a Future, then return
        // the resulting Future[Assertion] to ScalaTest:
        futureSum map { sum => assert(sum == 3) }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      test("addNow will immediately compute a sum of passed Ints") {
        val sum: Int = addNow(1, 2)
        // You can also write synchronous tests. The body
        // must have result type Assertion:
        assert(sum == 3)
      }
    }
    

    When you mark a test class with a tag annotation, ScalaTest will mark each test defined in that class with that tag. Thus, marking the AddSuite in the above example with the @Ignore tag annotation means that both tests in the class will be ignored. If you run the above AddSuite in the Scala interpreter, you'll see:

    scala> org.scalatest.run(new AddSuite)
    AddSuite:
    - addSoon will eventually compute a sum of passed Ints !!! IGNORED !!!
    - addNow will immediately compute a sum of passed Ints !!! IGNORED !!!
    

    Note that marking a test class as ignored won't prevent it from being discovered by ScalaTest. Ignored classes will be discovered and run, and all their tests will be reported as ignored. This is intended to keep the ignored class visible, to encourage the developers to eventually fix and “un-ignore” it. If you want to prevent a class from being discovered at all (on the JVM, not Scala.js), use the DoNotDiscover annotation instead.

    If you want to ignore all tests of a suite on Scala.js, where annotations can't be inspected at runtime, you'll need to change test to ignore at each test site. To make a suite non-discoverable on Scala.js, ensure it does not declare a public no-arg constructor. You can either declare a public constructor that takes one or more arguments, or make the no-arg constructor non-public. Because this technique will also make the suite non-discoverable on the JVM, it is a good approach for suites you want to run (but not be discoverable) on both Scala.js and the JVM.

    Informers

    One of the parameters to AsyncFunSuite's run method is a Reporter, which will collect and report information about the running suite of tests. Information about suites and tests that were run, whether tests succeeded or failed, and tests that were ignored will be passed to the Reporter as the suite runs. Most often the reporting done by default by AsyncFunSuite's methods will be sufficient, but occasionally you may wish to provide custom information to the Reporter from a test. For this purpose, an Informer that will forward information to the current Reporter is provided via the info parameterless method. You can pass the extra information to the Informer via its apply method. The Informer will then pass the information to the Reporter via an InfoProvided event. Here's an example that shows both a direct use as well as an indirect use through the methods of GivenWhenThen:

    package org.scalatest.examples.asyncfunsuite.info
    
    import collection.mutable
    import org.scalatest._
    
    class SetSuite extends AsyncFunSuite with GivenWhenThen {
    
      test("An element can be added to an empty mutable Set") {
    
        Given("an empty mutable Set")
        val set = mutable.Set.empty[String]
    
        When("an element is added")
        set += "clarity"
    
        Then("the Set should have size 1")
        assert(set.size === 1)
    
        And("the Set should contain the added element")
        assert(set.contains("clarity"))
    
        info("That's all folks!")
        succeed
      }
    }
    

    If you run this AsyncFunSuite from the interpreter, you will see the following output:

    scala> org.scalatest.run(new SetSuite)
    SetSuite:
    - an element can be added to an empty mutable Set
      + Given an empty mutable Set
      + When an element is added
      + Then the Set should have size 1
      + And the Set should contain the added element
      + That's all folks!
    

    Documenters

    AsyncFunSuite also provides a markup method that returns a Documenter, which allows you to send to the Reporter text formatted in Markdown syntax. You can pass the extra information to the Documenter via its apply method. The Documenter will then pass the information to the Reporter via an MarkupProvided event.

    Here's an example AsyncFunSuite that uses markup:

    package org.scalatest.examples.asyncfunsuite.markup
    
    import collection.mutable
    import org.scalatest._
    
    class SetSuite extends AsyncFunSuite with GivenWhenThen {
    
      markup { """
    
    Mutable Set
    -----------
    
    A set is a collection that contains no duplicate elements.
    
    To implement a concrete mutable set, you need to provide implementations
    of the following methods:
    
        def contains(elem: A): Boolean
        def iterator: Iterator[A]
        def += (elem: A): this.type
        def -= (elem: A): this.type
    
    If you wish that methods like `take`,
    `drop`, `filter` return the same kind of set,
    you should also override:
    
        def empty: This
    
    It is also good idea to override methods `foreach` and
    `size` for efficiency.
    
      """ }
    
      test("An element can be added to an empty mutable Set") {
    
        Given("an empty mutable Set")
        val set = mutable.Set.empty[String]
    
        When("an element is added")
        set += "clarity"
    
        Then("the Set should have size 1")
        assert(set.size === 1)
    
        And("the Set should contain the added element")
        assert(set.contains("clarity"))
    
        markup("This test finished with a **bold** statement!")
        succeed
      }
    }
    

    Although all of ScalaTest's built-in reporters will display the markup text in some form, the HTML reporter will format the markup information into HTML. Thus, the main purpose of markup is to add nicely formatted text to HTML reports. Here's what the above SetSpec would look like in the HTML reporter:

    Notifiers and alerters

    ScalaTest records text passed to info and markup during tests, and sends the recorded text in the recordedEvents field of test completion events like TestSucceeded and TestFailed. This allows string reporters (like the standard out reporter) to show info and markup text after the test name in a color determined by the outcome of the test. For example, if the test fails, string reporters will show the info and markup text in red. If a test succeeds, string reporters will show the info and markup text in green. While this approach helps the readability of reports, it means that you can't use info to get status updates from long running tests.

    To get immediate (i.e., non-recorded) notifications from tests, you can use note (a Notifier) and alert (an Alerter). Here's an example showing the differences:

    package org.scalatest.examples.asyncfunsuite.note
    
    import collection.mutable
    import org.scalatest._
    
    class SetSuite extends AsyncFunSuite {
    
      test("An element can be added to an empty mutable Set") {
    
        info("info is recorded")
        markup("markup is *also* recorded")
        note("notes are sent immediately")
        alert("alerts are also sent immediately")
    
        val set = mutable.Set.empty[String]
        set += "clarity"
        assert(set.size === 1)
        assert(set.contains("clarity"))
      }
    }
    

    Because note and alert information is sent immediately, it will appear before the test name in string reporters, and its color will be unrelated to the ultimate outcome of the test: note text will always appear in green, alert text will always appear in yellow. Here's an example:

    scala> org.scalatest.run(new SetSpec)
    SetSuite:
      + notes are sent immediately
      + alerts are also sent immediately
    - An element can be added to an empty mutable Set
      + info is recorded
      + markup is *also* recorded
    

    Another example is slowpoke notifications. If you find a test is taking a long time to complete, but you're not sure which test, you can enable slowpoke notifications. ScalaTest will use an Alerter to fire an event whenever a test has been running longer than a specified amount of time.

    In summary, use info and markup for text that should form part of the specification output. Use note and alert to send status notifications. (Because the HTML reporter is intended to produce a readable, printable specification, info and markup text will appear in the HTML report, but note and alert text will not.)

    Pending tests

    A pending test is one that has been given a name but is not yet implemented. The purpose of pending tests is to facilitate a style of testing in which documentation of behavior is sketched out before tests are written to verify that behavior (and often, before the behavior of the system being tested is itself implemented). Such sketches form a kind of specification of what tests and functionality to implement later.

    To support this style of testing, a test can be given a name that specifies one bit of behavior required by the system being tested. At the end of the test, it can call method pending, which will cause it to complete abruptly with TestPendingException.

    Because tests in ScalaTest can be designated as pending with TestPendingException, both the test name and any information sent to the reporter when running the test can appear in the report of a test run. (In other words, the code of a pending test is executed just like any other test.) However, because the test completes abruptly with TestPendingException, the test will be reported as pending, to indicate the actual test, and possibly the functionality, has not yet been implemented. Here's an example:

    package org.scalatest.examples.asyncfunsuite.pending
    
    import org.scalatest.AsyncFunSuite
    import scala.concurrent.Future
    
    class AddSuite extends AsyncFunSuite {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      test("addSoon will eventually compute a sum of passed Ints") (pending)
    
      def addNow(addends: Int*): Int = addends.sum
    
      test("addNow will immediately compute a sum of passed Ints") {
        val sum: Int = addNow(1, 2)
        // You can also write synchronous tests. The body
        // must have result type Assertion:
        assert(sum == 3)
      }
    }
    

    (Note: "(pending)" is the body of the test. Thus the test contains just one statement, an invocation of the pending method, which throws TestPendingException.) If you run this version of AddSuite with:

    scala> org.scalatest.run(new AddSuite)
    

    It will run both tests, but report that first test is pending. You'll see:

    AddSuite:
    - addSoon will eventually compute a sum of passed Ints (pending)
    - addNow will immediately compute a sum of passed Ints
    

    One difference between an ignored test and a pending one is that an ignored test is intended to be used during significant refactorings of the code under test, when tests break and you don't want to spend the time to fix all of them immediately. You can mark some of those broken tests as ignored temporarily, so that you can focus the red bar on just failing tests you actually want to fix immediately. Later you can go back and fix the ignored tests. In other words, by ignoring some failing tests temporarily, you can more easily notice failed tests that you actually want to fix. By contrast, a pending test is intended to be used before a test and/or the code under test is written. Pending indicates you've decided to write a test for a bit of behavior, but either you haven't written the test yet, or have only written part of it, or perhaps you've written the test but don't want to implement the behavior it tests until after you've implemented a different bit of behavior you realized you need first. Thus ignored tests are designed to facilitate refactoring of existing code whereas pending tests are designed to facilitate the creation of new code.

    One other difference between ignored and pending tests is that ignored tests are implemented as a test tag that is excluded by default. Thus an ignored test is never executed. By contrast, a pending test is implemented as a test that throws TestPendingException (which is what calling the pending method does). Thus the body of pending tests are executed up until they throw TestPendingException.

    Tagging tests

    An AsyncFunSuite's tests may be classified into groups by tagging them with string names. As with any suite, when executing an AsyncFunSuite, groups of tests can optionally be included and/or excluded. To tag an AsyncFunSuite's tests, you pass objects that extend class org.scalatest.Tag to methods that register tests. Class Tag takes one parameter, a string name. If you have created tag annotation interfaces as described in the Tag documentation, then you will probably want to use tag names on your test functions that match. To do so, simply pass the fully qualified names of the tag interfaces to the Tag constructor. For example, if you've defined a tag annotation interface with fully qualified name, com.mycompany.tags.DbTest, then you could create a matching tag for AsyncFunSuites like this:

    package org.scalatest.examples.asyncfunsuite.tagging
    
    import org.scalatest.Tag
    
    object DbTest extends Tag("com.mycompany.tags.DbTest")
    

    Given these definitions, you could place AsyncFunSuite tests into groups with tags like this:

    import org.scalatest.AsyncFunSuite
    import org.scalatest.tagobjects.Slow
    import scala.concurrent.Future
    
    class AddSuite extends AsyncFunSuite {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      test("addSoon will eventually compute a sum of passed Ints", Slow) {
        val futureSum: Future[Int] = addSoon(1, 2)
        // You can map assertions onto a Future, then return
        // the resulting Future[Assertion] to ScalaTest:
        futureSum map { sum => assert(sum == 3) }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      test("addNow will immediately compute a sum of passed Ints",
          Slow, DbTest) {
    
        val sum: Int = addNow(1, 2)
        // You can also write synchronous tests. The body
        // must have result type Assertion:
        assert(sum == 3)
      }
    }
    

    This code marks both tests with the org.scalatest.tags.Slow tag, and the second test with the com.mycompany.tags.DbTest tag.

    The run method takes a Filter, whose constructor takes an optional Set[String] called tagsToInclude and a Set[String] called tagsToExclude. If tagsToInclude is None, all tests will be run except those those belonging to tags listed in the tagsToExclude Set. If tagsToInclude is defined, only tests belonging to tags mentioned in the tagsToInclude set, and not mentioned in tagsToExclude, will be run.

    It is recommended, though not required, that you create a corresponding tag annotation when you create a Tag object. A tag annotation (on the JVM, not Scala.js) allows you to tag all the tests of an AsyncFunSuite in one stroke by annotating the class. For more information and examples, see the documentation for class Tag. On Scala.js, to tag all tests of a suite, you'll need to tag each test individually at the test site.

    Shared fixtures

    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.

    ScalaTest recommends three techniques to eliminate such code duplication in async styles:

    • Refactor using Scala
    • Override withFixture
    • Mix in a before-and-after trait

    Each technique is geared towards helping you reduce code duplication without introducing instance vars, shared mutable objects, or other dependencies between tests. Eliminating shared mutable state across tests will make your test code easier to reason about and eliminate the need to synchronize access to shared mutable state on the JVM.

    The following sections describe these techniques, including explaining the recommended usage for each. But first, here's a table summarizing the options:

    Refactor using Scala when different tests need different fixtures.
    get-fixture methods The extract method refactor helps you create a fresh instances of mutable fixture objects in each test that needs them, but doesn't help you clean them up when you're done.
    loan-fixture methods Factor out dupicate code with the loan pattern when different tests need different fixtures that must be cleaned up afterwards.
    Override withFixture when most or all tests need the same fixture.
    withFixture(NoArgAsyncTest) The recommended default approach when most or all tests need the same fixture treatment. This general technique allows you, for example, to perform side effects at the beginning and end of all or most tests, transform the outcome of tests, retry tests, make decisions based on test names, tags, or other test data. Use this technique unless:
    Different tests need different fixtures (refactor using Scala instead)
    An exception in fixture code should abort the suite, not fail the test (use a before-and-after trait instead)
    You have objects to pass into tests (override withFixture(OneArgAsyncTest) instead)
    withFixture(OneArgAsyncTest) Use when you want to pass the same fixture object or objects as a parameter into all or most tests.
    Mix in a before-and-after trait when you want an aborted suite, not a failed test, if the fixture code fails.
    BeforeAndAfter Use this boilerplate-buster when you need to perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.
    BeforeAndAfterEach Use when you want to stack traits that perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.

    Calling get-fixture methods

    If you need to create the same mutable fixture objects in multiple tests, and don't need to clean them up after using them, the simplest approach is to write one or more get-fixture methods. A get-fixture method returns a new instance of a needed fixture object (or a holder object containing multiple fixture objects) each time it is called. You can call a get-fixture method at the beginning of each test that needs the fixture, storing the returned object or objects in local variables. Here's an example:

    package org.scalatest.examples.asyncfunsuite.getfixture
    
    import org.scalatest.AsyncFunSuite
    import collection.mutable.ListBuffer
    import scala.concurrent.Future
    
    class ExampleSuite extends AsyncFunSuite {
    
      def fixture: Future[String] = Future { "ScalaTest is " }
    
      test("Testing should be easy") {
        val future = fixture
        val result = future map { s => s + "easy!" }
        result map { s =>
          assert(s === "ScalaTest is easy!")
        }
      }
    
      test("Testing should be fun") {
        val future = fixture
        val result = future map { s => s + "fun!" }
        result map { s =>
          assert(s === "ScalaTest is fun!")
        }
      }
    }
    

    If you need to configure fixture objects differently in different tests, you can pass configuration into the get-fixture method. For example, you could pass in an initial value for a fixture object as a parameter to the get-fixture method.

    Overriding withFixture(NoArgAsyncTest)

    Although the get-fixture method approach takes care of setting up a fixture at the beginning of each test, it doesn't address the problem of cleaning up a fixture at the end of the test. If you just need to perform a side-effect at the beginning or end of a test, and don't need to actually pass any fixture objects into the test, you can override withFixture(NoArgAsyncTest), a method defined in trait AsyncTestSuite, a supertrait of AsyncFunSuite.

    Trait AsyncFunSuite's runTest method passes a no-arg async test function to withFixture(NoArgAsyncTest). It is withFixture's responsibility to invoke that test function. The default implementation of withFixture simply invokes the function and returns the result, like this:

    // Default implementation in trait AsyncTestSuite
    protected def withFixture(test: NoArgAsyncTest): FutureOutcome = {
      test()
    }
    

    You can, therefore, override withFixture to perform setup before invoking the test function, and/or perform cleanup after the test completes. The recommended way to ensure cleanup is performed after a test completes is to use the complete-lastly syntax, defined in supertrait CompleteLastly. The complete-lastly syntax will ensure that cleanup will occur whether future-producing code completes abruptly by throwing an exception, or returns normally yielding a future. In the latter case, complete-lastly will register the cleanup code to execute asynchronously when the future completes.

    The withFixture method is designed to be stacked, and to enable this, you should always call the super implementation of withFixture, 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)”, like this:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      complete {
        super.withFixture(test) // Invoke the test function
      } lastly {
        // Perform cleanup here
      }
    }
    

    If you have no cleanup to perform, you can write withFixture like this instead:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      super.withFixture(test) // Invoke the test function
    }
    

    If you want to perform an action only for certain outcomes, you'll need to register code performing that action as a callback on the Future using one of Future's registration methods: onComplete, onSuccess, or onFailure. Note that if a test fails, that will be treated as a scala.util.Success(org.scalatest.Failed). So if you want to perform an action if a test fails, for example, you'd register the callback using onSuccess.

    Here's an example in which withFixture(NoArgAsyncTest) is used to take a snapshot of the working directory if a test fails, and send that information to the standard output stream:

    package org.scalatest.examples.asyncfunsuite.noargasynctest
    
    import java.io.File
    import org.scalatest._
    import scala.concurrent.Future
    
    class ExampleSuite extends AsyncFunSuite {
    
      override def withFixture(test: NoArgAsyncTest) = {
    
        super.withFixture(test) onFailedThen { _ =>
          val currDir = new File(".")
          val fileNames = currDir.list()
          info("Dir snapshot: " + fileNames.mkString(", "))
        }
      }
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      test("This test should succeed") {
        addSoon(1, 1) map { sum => assert(sum === 2) }
      }
    
      test("This test should fail") {
        addSoon(1, 1) map { sum => assert(sum === 3) }
      }
    }
    

    Running this version of ExampleSuite in the interpreter in a directory with two files, hello.txt and world.txt would give the following output:

    scala> org.scalatest.run(new ExampleSuite)
    ExampleSuite:
    - this test should succeed
    Dir snapshot: hello.txt, world.txt
    - this test should fail *** FAILED ***
      2 did not equal 3 (:33)
    

    Note that the NoArgAsyncTest passed to withFixture, in addition to an apply method that executes the test, also includes the test name and the config map passed to runTest. Thus you can also use the test name and configuration objects in your withFixture implementation.

    Lastly, if you want to transform the outcome in some way in withFixture, you'll need to use either the map or transform methods of Future, like this:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      val futureOutcome = super.withFixture(test) // Invoke the test function
    
      futureOutcome change { outcome =>
        // transform the outcome into a new outcome here
      }
    }
    

    Note that a NoArgAsyncTest's apply method will return a scala.util.Failure only if the test completes abruptly with a "test-fatal" exception (such as OutOfMemoryError) that should cause the suite to abort rather than the test to fail. Thus usually you would use map to transform future outcomes, not transform, so that such test-fatal exceptions pass through unchanged. The suite will abort asynchronously with any exception returned from NoArgAsyncTest's apply method in a scala.util.Failure.

    Calling loan-fixture methods

    If you need to both pass a fixture object into a test and perform cleanup at the end of the test, you'll need to use the loan pattern. If different tests need different fixtures that require cleanup, you can implement the loan pattern directly by writing loan-fixture methods. A loan-fixture method takes a function whose body forms part or all of a test's code. It creates a fixture, passes it to the test code by invoking the function, then cleans up the fixture after the function returns.

    The following example shows three tests that use two fixtures, a database and a file. Both require cleanup after, so each is provided via a loan-fixture method. (In this example, the database is simulated with a StringBuffer.)

    package org.scalatest.examples.asyncfunsuite.loanfixture
    
    import java.util.concurrent.ConcurrentHashMap
    
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    object DbServer { // Simulating a database server
      type Db = StringBuffer
      private final val databases = new ConcurrentHashMap[String, Db]
      def createDb(name: String): Db = {
        val db = new StringBuffer // java.lang.StringBuffer is thread-safe
        databases.put(name, db)
        db
      }
      def removeDb(name: String): Unit = {
        databases.remove(name)
      }
    }
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    import org.scalatest._
    import DbServer._
    import java.util.UUID.randomUUID
    
    class ExampleSuite extends AsyncFunSuite {
    
      def withDatabase(testCode: Future[Db] => Future[Assertion]) = {
        val dbName = randomUUID.toString // generate a unique db name
        val futureDb = Future { createDb(dbName) } // create the fixture
        complete {
          val futurePopulatedDb =
            futureDb map { db =>
              db.append("ScalaTest is ") // perform setup
            }
          testCode(futurePopulatedDb) // "loan" the fixture to the test code
        } lastly {
          removeDb(dbName) // ensure the fixture will be cleaned up
        }
      }
    
      def withActor(testCode: StringActor => Future[Assertion]) = {
        val actor = new StringActor
        complete {
          actor ! Append("ScalaTest is ") // set up the fixture
          testCode(actor) // "loan" the fixture to the test code
        } lastly {
          actor ! Clear // ensure the fixture will be cleaned up
        }
      }
    
      // This test needs the actor fixture
      test("Testing should be productive") {
        withActor { actor =>
          actor ! Append("productive!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s === "ScalaTest is productive!")
          }
        }
      }
    
      // This test needs the database fixture
      test("Test code should be readable") {
        withDatabase { futureDb =>
          futureDb map { db =>
            db.append("readable!")
            assert(db.toString === "ScalaTest is readable!")
          }
        }
      }
    
      // This test needs both the actor and the database
      test("Test code should be clear and concise") {
        withDatabase { futureDb =>
          withActor { actor => // loan-fixture methods compose
            actor ! Append("concise!")
            val futureString = actor ? GetValue
            val futurePair: Future[(Db, String)] =
              futureDb zip futureString
            futurePair map { case (db, s) =>
              db.append("clear!")
              assert(db.toString === "ScalaTest is clear!")
              assert(s === "ScalaTest is concise!")
            }
          }
        }
      }
    }
    

    As demonstrated by the last test, loan-fixture methods compose. Not only do loan-fixture methods allow you to give each test the fixture it needs, they allow you to give a test multiple fixtures and clean everything up afterwards.

    Also demonstrated in this example is the technique of giving each test its own "fixture sandbox" to play in. When your fixtures involve external side-effects, like creating databases, it is a good idea to give each database a unique name as is done in this example. This keeps tests completely isolated, allowing you to run them in parallel if desired.

    Overriding withFixture(OneArgTest)

    If all or most tests need the same fixture, you can avoid some of the boilerplate of the loan-fixture method approach by using a fixture.AsyncTestSuite and overriding withFixture(OneArgAsyncTest). Each test in a fixture.AsyncTestSuite takes a fixture as a parameter, allowing you to pass the fixture into the test. You must indicate the type of the fixture parameter by specifying FixtureParam, and implement a withFixture method that takes a OneArgAsyncTest. This withFixture method is responsible for invoking the one-arg async test function, so you can perform fixture set up before invoking and passing the fixture into the test function, and ensure clean up is performed after the test completes.

    To enable the stacking of traits that define withFixture(NoArgAsyncTest), it is a good idea to let withFixture(NoArgAsyncTest) invoke the test function instead of invoking the test function directly. To do so, you'll need to convert the OneArgAsyncTest to a NoArgAsyncTest. You can do that by passing the fixture object to the toNoArgAsyncTest method of OneArgAsyncTest. In other words, instead of writing “test(theFixture)”, you'd delegate responsibility for invoking the test function to the withFixture(NoArgAsyncTest) method of the same instance by writing:

    withFixture(test.toNoArgAsyncTest(theFixture))
    

    Here's a complete example:

    package org.scalatest.examples.asyncfunsuite.oneargasynctest
    
    import org.scalatest._
    import java.io._
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class ExampleSuite extends fixture.AsyncFunSuite {
    
      type FixtureParam = StringActor
    
      def withFixture(test: OneArgAsyncTest): FutureOutcome = {
    
        val actor = new StringActor
        complete {
          actor ! Append("ScalaTest is ") // set up the fixture
          withFixture(test.toNoArgAsyncTest(actor))
        } lastly {
          actor ! Clear // ensure the fixture will be cleaned up
        }
      }
    
      test("Testing should be easy") { actor =>
        actor ! Append("easy!")
        val futureString = actor ? GetValue
        futureString map { s =>
          assert(s === "ScalaTest is easy!")
        }
      }
    
      test("Testing should be fun") { actor =>
        actor ! Append("fun!")
        val futureString = actor ? GetValue
        futureString map { s =>
          assert(s === "ScalaTest is fun!")
        }
      }
    }
    

    In this example, the tests required one fixture object, a StringActor. If your tests need multiple fixture objects, you can simply define the FixtureParam type to be a tuple containing the objects or, alternatively, a case class containing the objects. For more information on the withFixture(OneArgAsyncTest) technique, see the documentation for fixture.AsyncFunSuite.

    Mixing in BeforeAndAfter

    In all the shared fixture examples shown so far, the activities of creating, setting up, and cleaning up the fixture objects have been performed during the test. This means that if an exception occurs during any of these activities, it will be reported as a test failure. Sometimes, however, you may want setup to happen before the test starts, and cleanup after the test has completed, so that if an exception occurs during setup or cleanup, the entire suite aborts and no more tests are attempted. The simplest way to accomplish this in ScalaTest is to mix in trait BeforeAndAfter. With this trait you can denote a bit of code to run before each test with before and/or after each test each test with after, like this:

    package org.scalatest.examples.asyncfunsuite.beforeandafter
    
    import org.scalatest.AsyncFunSuite
    import org.scalatest.BeforeAndAfter
    import collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class ExampleSuite extends AsyncFunSuite with BeforeAndAfter {
    
      final val actor = new StringActor
    
      before {
        actor ! Append("ScalaTest is ") // set up the fixture
      }
    
      after {
        actor ! Clear // clean up the fixture
      }
    
      test("testing should be easy") {
        actor ! Append("easy!")
        val futureString = actor ? GetValue
        futureString map { s =>
          assert(s === "ScalaTest is easy!")
        }
      }
    
      test("testing should be fun") {
        actor ! Append("fun!")
        val futureString = actor ? GetValue
        futureString map { s =>
          assert(s === "ScalaTest is fun!")
        }
      }
    }
    

    Note that the only way before and after code can communicate with test code is via some side-effecting mechanism, commonly by reassigning instance vars or by changing the state of mutable objects held from instance vals (as in this example). If using instance vars or mutable objects held from instance vals you wouldn't be able to run tests in parallel in the same instance of the test class (on the JVM, not Scala.js) unless you synchronized access to the shared, mutable state.

    Note that on the JVM, if you override ScalaTest's default serial execution context, you will likely need to worry about synchronizing access to shared mutable fixture state, because the execution context may assign different threads to process different Future transformations. Although access to mutable state along the same linear chain of Future transformations need not be synchronized, it can be difficult to spot cases where these constraints are violated. The best approach is to use only immutable objects when transforming Futures. When that's not practical, involve only thread-safe mutable objects, as is done in the above example. On Scala.js, by contrast, you need not worry about thread synchronization, because in effect only one thread exists.

    Although BeforeAndAfter provides a minimal-boilerplate way to execute code before and after tests, it isn't designed to enable stackable traits, because the order of execution would be non-obvious. If you want to factor out before and after code that is common to multiple test suites, you should use trait BeforeAndAfterEach instead, as shown later in the next section, composing fixtures by stacking traits.

    Composing fixtures by stacking traits

    In larger projects, teams often end up with several different fixtures that test classes need in different combinations, and possibly initialized (and cleaned up) in different orders. A good way to accomplish this in ScalaTest is to factor the individual fixtures into traits that can be composed using the stackable trait pattern. This can be done, for example, by placing withFixture methods in several traits, each of which call super.withFixture. Here's an example in which the StringBuilderActor and StringBufferActor fixtures used in the previous examples have been factored out into two stackable fixture traits named Builder and Buffer:

    package org.scalatest.examples.asyncfunsuite.composingwithasyncfixture
    
    import org.scalatest._
    import org.scalatest.SuiteMixin
    import collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringBuilderActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class StringBufferActor {
      private final val buf = ListBuffer.empty[String]
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => buf += value
            case Clear => buf.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[List[String]] =
        Future {
          synchronized { buf.toList }
        }
    }
    
    trait Builder extends AsyncTestSuiteMixin { this: AsyncTestSuite =>
    
      final val builderActor = new StringBuilderActor
    
      abstract override def withFixture(test: NoArgAsyncTest) = {
        builderActor ! Append("ScalaTest is ")
        complete {
          super.withFixture(test) // To be stackable, must call super.withFixture
        } lastly {
          builderActor ! Clear
        }
      }
    }
    
    trait Buffer extends AsyncTestSuiteMixin { this: AsyncTestSuite =>
    
      final val bufferActor = new StringBufferActor
    
      abstract override def withFixture(test: NoArgAsyncTest) = {
        complete {
          super.withFixture(test) // To be stackable, must call super.withFixture
        } lastly {
          bufferActor ! Clear
        }
      }
    }
    
    class ExampleSuite extends AsyncFunSuite with Builder with Buffer {
    
      test("Testing should be easy") {
        builderActor ! Append("easy!")
        val futureString = builderActor ? GetValue
        val futureList = bufferActor ? GetValue
        val futurePair: Future[(String, List[String])] = futureString zip futureList
        futurePair map { case (str, lst) =>
          assert(str === "ScalaTest is easy!")
          assert(lst.isEmpty)
          bufferActor ! Append("sweet")
          succeed
        }
      }
    
      test("Testing should be fun") {
        builderActor ! Append("fun!")
        val futureString = builderActor ? GetValue
        val futureList = bufferActor ? GetValue
        val futurePair: Future[(String, List[String])] = futureString zip futureList
        futurePair map { case (str, lst) =>
          assert(str === "ScalaTest is fun!")
          assert(lst.isEmpty)
          bufferActor ! Append("awesome")
          succeed
        }
      }
    }
    

    By mixing in both the Builder and Buffer traits, ExampleSuite gets both fixtures, which will be initialized before each test and cleaned up after. The order the traits are mixed together determines the order of execution. In this case, Builder is “super” to Buffer. If you wanted Buffer to be “super” to Builder, you need only switch the order you mix them together, like this:

    class Example2Suite extends AsyncFunSuite with Buffer with Builder
    

    If you only need one fixture you mix in only that trait:

    class Example3Suite extends AsyncFunSuite with Builder
    

    Another way to create stackable fixture traits is by extending the BeforeAndAfterEach and/or BeforeAndAfterAll traits. BeforeAndAfterEach has 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). Similarly, BeforeAndAfterAll has a beforeAll method that will be run before all tests, and an afterAll method that will be run after all tests. Here's what the previously shown example would look like if it were rewritten to use the BeforeAndAfterEach methods instead of withFixture:

    package org.scalatest.examples.asyncfunsuite.composingbeforeandaftereach
    
    import org.scalatest._
    import org.scalatest.BeforeAndAfterEach
    import collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringBuilderActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class StringBufferActor {
      private final val buf = ListBuffer.empty[String]
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => buf += value
            case Clear => buf.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[List[String]] =
        Future {
          synchronized { buf.toList }
        }
    }
    
    trait Builder extends BeforeAndAfterEach { this: Suite =>
    
      final val builderActor = new StringBuilderActor
    
      override def beforeEach() {
        builderActor ! 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 builderActor ! Clear
      }
    }
    
    trait Buffer extends BeforeAndAfterEach { this: Suite =>
    
      final val bufferActor = new StringBufferActor
    
      override def afterEach() {
        try super.afterEach() // To be stackable, must call super.afterEach
        finally bufferActor ! Clear
      }
    }
    
    class ExampleSuite extends AsyncFunSuite with Builder with Buffer {
    
      test("Testing should be easy") {
        builderActor ! Append("easy!")
        val futureString = builderActor ? GetValue
        val futureList = bufferActor ? GetValue
        val futurePair: Future[(String, List[String])] = futureString zip futureList
        futurePair map { case (str, lst) =>
          assert(str === "ScalaTest is easy!")
          assert(lst.isEmpty)
          bufferActor ! Append("sweet")
          succeed
        }
      }
    
      test("Testing should be fun") {
        builderActor ! Append("fun!")
        val futureString = builderActor ? GetValue
        val futureList = bufferActor ? GetValue
        val futurePair: Future[(String, List[String])] = futureString zip futureList
        futurePair map { case (str, lst) =>
          assert(str === "ScalaTest is fun!")
          assert(lst.isEmpty)
          bufferActor ! Append("awesome")
          succeed
        }
      }
    }
    

    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 difference between stacking traits that extend BeforeAndAfterEach versus traits that implement withFixture is that setup and cleanup code happens before and after the test in BeforeAndAfterEach, but at the beginning and end of the test in withFixture. Thus if a withFixture method completes abruptly with an exception, it is considered a failed test. By contrast, if any of the beforeEach or afterEach methods of BeforeAndAfterEach complete abruptly, it is considered an aborted suite, which will result in a SuiteAborted event.

    Shared tests

    Sometimes you may want to run the same test code on different fixture objects. In other words, you may want to write tests that are "shared" by different fixture objects. To accomplish this in an AsyncFunSuite, you first place shared tests in behavior functions. These behavior functions will be invoked during the construction phase of any AsyncFunSuite that uses them, so that the tests they contain will be registered as tests in that AsyncFunSuite. For example, given this StackActor class:

    package org.scalatest.examples.asyncfunsuite.sharedtests
    
    import scala.collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Stack operations
    case class Push[T](value: T)
    sealed abstract class StackOp
    case object Pop extends StackOp
    case object Peek extends StackOp
    case object Size extends StackOp
    
    // Stack info
    case class StackInfo[T](top: Option[T], size: Int, max: Int) {
      require(size >= 0, "size was less than zero")
      require(max >= size, "max was less than size")
      val isFull: Boolean = size == max
      val isEmpty: Boolean = size == 0
    }
    
    class StackActor[T](Max: Int, name: String) {
    
      private final val buf = new ListBuffer[T]
    
      def !(push: Push[T]): Unit =
        synchronized {
          if (buf.size != Max)
            buf.prepend(push.value)
          else
            throw new IllegalStateException("can't push onto a full stack")
        }
    
      def ?(op: StackOp)(implicit c: ExecutionContext): Future[StackInfo[T]] =
        synchronized {
          op match {
            case Pop =>
              if (buf.size != 0)
                Future { StackInfo(Some(buf.remove(0)), buf.size, Max) }
              else
                throw new IllegalStateException("can't pop an empty stack")
            case Peek =>
              if (buf.size != 0)
                Future { StackInfo(Some(buf(0)), buf.size, Max) }
              else
                throw new IllegalStateException("can't peek an empty stack")
            case Size =>
              Future { StackInfo(None, buf.size, Max) }
          }
        }
    
      override def toString: String = name
    }
    

    You may want to test the stack represented by the StackActor class in different states: empty, full, with one item, with one item less than capacity, etc. You may find you have several tests that make sense any time the stack is non-empty. Thus you'd ideally want to run those same tests for three stack fixture objects: a full stack, a stack with a one item, and a stack with one item less than capacity. With shared tests, you can factor these tests out into a behavior function, into which you pass the stack fixture to use when running the tests. So in your AsyncFunSuite for StackActor, you'd invoke the behavior function three times, passing in each of the three stack fixtures so that the shared tests are run for all three fixtures.

    You can define a behavior function that encapsulates these shared tests inside the AsyncFunSuite that uses them. If they are shared between different AsyncFunSuites, however, you could also define them in a separate trait that is mixed into each AsyncFunSuite that uses them. For example, here the nonEmptyStackActor behavior function (in this case, a behavior method) is defined in a trait along with another method containing shared tests for non-full stacks:

    import org.scalatest.AsyncFunSuite
    
    trait AsyncFunSuiteStackBehaviors { this: AsyncFunSuite =>
    
      def nonEmptyStackActor(createNonEmptyStackActor: => StackActor[Int],
            lastItemAdded: Int, name: String): Unit = {
    
        test("Size is fired at non-empty stack actor: " + name) {
          val stackActor = createNonEmptyStackActor
          val futureStackInfo = stackActor ? Size
          futureStackInfo map { stackInfo =>
            assert(!stackInfo.isEmpty)
          }
        }
    
        test("Peek is fired at non-empty stack actor: " + name) {
          val stackActor = createNonEmptyStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePeek <- stackActor ? Size
              afterPeek <- stackActor ? Peek
            } yield (beforePeek, afterPeek)
          futurePair map { case (beforePeek, afterPeek) =>
            assert(afterPeek.top === Some(lastItemAdded))
            assert(afterPeek.size === beforePeek.size)
          }
        }
    
        test("Pop is fired at non-empty stack actor: " + name) {
          val stackActor = createNonEmptyStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePop <- stackActor ? Size
              afterPop <- stackActor ? Pop
            } yield (beforePop, afterPop)
          futurePair map { case (beforePop, afterPop) =>
            assert(afterPop.top === Some(lastItemAdded))
            assert(afterPop.size === beforePop.size - 1)
          }
        }
      }
    
      def nonFullStackActor(createNonFullStackActor: => StackActor[Int], name: String): Unit = {
    
        test("non-full stack actor is not full: " + name) {
          val stackActor = createNonFullStackActor
          val futureStackInfo = stackActor ? Size
          futureStackInfo map { stackInfo =>
            assert(!stackInfo.isFull)
          }
        }
    
        test("Push is fired at non-full stack actor: " + name) {
          val stackActor = createNonFullStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePush <- stackActor ? Size
              afterPush <- { stackActor ! Push(7); stackActor ? Peek }
            } yield (beforePush, afterPush)
          futurePair map { case (beforePush, afterPush) =>
            assert(afterPush.top === Some(7))
            assert(afterPush.size === beforePush.size + 1)
          }
        }
      }
    }
    

    Given these behavior functions, you could invoke them directly, but AsyncFunSuite offers a DSL for the purpose, which looks like this:

    testsFor(nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName))
    testsFor(nonFullStackActor(almostEmptyStackActor, almostEmptyStackActorName))
    

    Here's an example:

    class StackSuite extends AsyncFunSuite with AsyncFunSuiteStackBehaviors {
    
      val Max = 10
      val LastValuePushed = Max - 1
    
      // Stack fixture creation methods
      val emptyStackActorName = "empty stack actor"
      def emptyStackActor = new StackActor[Int](Max, emptyStackActorName )
    
      val fullStackActorName = "full stack actor"
      def fullStackActor = {
        val stackActor = new StackActor[Int](Max, fullStackActorName )
        for (i <- 0 until Max)
          stackActor ! Push(i)
        stackActor
      }
    
      val almostEmptyStackActorName = "almost empty stack actor"
      def almostEmptyStackActor = {
        val stackActor = new StackActor[Int](Max, almostEmptyStackActorName )
        stackActor ! Push(LastValuePushed)
        stackActor
      }
    
      val almostFullStackActorName = "almost full stack actor"
      def almostFullStackActor = {
        val stackActor = new StackActor[Int](Max, almostFullStackActorName)
        for (i <- 1 to LastValuePushed)
          stackActor ! Push(i)
        stackActor
      }
    
      test("an empty stack actor is empty") {
        val stackActor = emptyStackActor
        val futureStackInfo = stackActor ? Size
        futureStackInfo map { stackInfo =>
          assert(stackInfo.isEmpty)
        }
      }
    
      test("Peek is fired at an empty stack actor") {
        recoverToSucceededIf[IllegalStateException] {
          emptyStackActor ? Peek
        }
      }
    
      test("Pop is fired at an empty stack actor") {
        recoverToSucceededIf[IllegalStateException] {
          emptyStackActor ? Pop
        }
      }
    
      testsFor(nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName))
      testsFor(nonFullStackActor(almostEmptyStackActor, almostEmptyStackActorName))
    
      testsFor(nonEmptyStackActor(almostFullStackActor, LastValuePushed, almostFullStackActorName))
      testsFor(nonFullStackActor(almostFullStackActor, almostFullStackActorName))
    
      test("a full stack actor is full") {
        val stackActor = fullStackActor
        val futureStackInfo = stackActor ? Size
        futureStackInfo map { stackInfo =>
          assert(stackInfo.isFull)
        }
      }
    
      testsFor(nonEmptyStackActor(fullStackActor, LastValuePushed, fullStackActorName))
    
      test("Push is fired at a full stack actor") {
        val stackActor = fullStackActor
        assertThrows[IllegalStateException] {
          stackActor ! Push(10)
        }
      }
    }
    

    If you load these classes into the Scala interpreter (with scalatest's JAR file on the class path), and execute it, you'll see:

    scala> org.scalatest.run(new StackSuite)
    StackSuite:
    StackSuite:
    - an empty stack actor is empty
    - Peek is fired at an empty stack actor
    - Pop is fired at an empty stack actor
    - Size is fired at non-empty stack actor: almost empty stack actor
    - Peek is fired at non-empty stack actor: almost empty stack actor
    - Pop is fired at non-empty stack actor: almost empty stack actor
    - non-full stack actor is not full: almost empty stack actor
    - Push is fired at non-full stack actor: almost empty stack actor
    - Size is fired at non-empty stack actor: almost full stack actor
    - Peek is fired at non-empty stack actor: almost full stack actor
    - Pop is fired at non-empty stack actor: almost full stack actor
    - non-full stack actor is not full: almost full stack actor
    - Push is fired at non-full stack actor: almost full stack actor
    - a full stack actor is full
    - Size is fired at non-empty stack actor: full stack actor
    - Peek is fired at non-empty stack actor: full stack actor
    - Pop is fired at non-empty stack actor: full stack actor
    - Push is fired at a full stack actor
    

    One thing to keep in mind when using shared tests is that in ScalaTest, each test in a suite must have a unique name. If you register the same tests repeatedly in the same suite, one problem you may encounter is an exception at runtime complaining that multiple tests are being registered with the same test name. In a AsyncFunSuite there is no nesting construct analogous to AsyncFunSpec's describe clause. Therefore, you need to do a bit of extra work to ensure that the test names are unique. If a duplicate test name problem shows up in an AsyncFunSuite, you'll need to pass in a prefix or suffix string to add to each test name. You can call toString on the shared fixture object, or pass this string the same way you pass any other data needed by the shared tests. This is the approach taken by the previous AsyncFunSuiteStackBehaviors example.

    Given this AsyncFunSuiteStackBehaviors trait, calling it with the stackWithOneItem fixture, like this:

    testsFor(nonEmptyStackActor(almostFullStackActor, LastValuePushed, almostFullStackActorName))
    

    yields test names:

    • Size is fired at non-empty stack actor: almost empty stack actor
    • Peek is fired at non-empty stack actor: almost empty stack actor
    • Pop is fired at non-empty stack actor: almost empty stack actor

    Whereas calling it with the stackWithOneItemLessThanCapacity fixture, like this:

    testsFor(nonEmptyStack(stackWithOneItemLessThanCapacity, lastValuePushed))
    

    yields different test names:

    • Size is fired at non-empty stack actor: almost full stack actor
    • Peek is fired at non-empty stack actor: almost full stack actor
    • Pop is fired at non-empty stack actor: almost full stack actor
  16. trait AsyncFunSuiteLike extends AsyncTestSuite with AsyncTestRegistration with Informing with Notifying with Alerting with Documenting

    Permalink

    Implementation trait for class AsyncFunSuite, which represents a suite of tests in which each test is represented as a function value.

    Implementation trait for class AsyncFunSuite, which represents a suite of tests in which each test is represented as a function value.

    AsyncFunSuite 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 AsyncFunSuite into some other class, you can use this trait instead, because class AsyncFunSuite does nothing more than extend this trait and add a nice toString implementation.

    See the documentation of the class for a detailed overview of AsyncFunSuite.

    Annotations
    @JSExportDescendentClasses( true ) @Finders()
  17. trait AsyncTestRegistration extends AnyRef

    Permalink

    Trait declaring methods that can be used to register by-name test functions that have result type Future[Assertion].

    Trait declaring methods that can be used to register by-name test functions that have result type Future[Assertion].

  18. trait AsyncTestSuite extends Suite with RecoverMethods with CompleteLastly

    Permalink

    The base trait of ScalaTest's asynchronous testing styles, which defines a withFixture lifecycle method that accepts as its parameter a test function that returns a FutureOutcome.

    The base trait of ScalaTest's asynchronous testing styles, which defines a withFixture lifecycle method that accepts as its parameter a test function that returns a FutureOutcome.

    The withFixture method add by this trait has the following signature and implementation:

    def withFixture(test: NoArgAsyncTest): FutureOutcome = {
      test()
    }
    

    This trait enables testing of asynchronous code without blocking. Instead of returning Outcome like TestSuite's withFixture, this trait's withFixture method returns a FutureOutcome. Similarly, the apply method of test function interface, NoArgAsyncTest, returns FutureOutcome:

    // In trait NoArgAsyncTest:
    def apply(): FutureOutcome
    

    The withFixture method supports async testing, because when the test function returns, the test body has not necessarily finished execution.

    The recommended way to ensure cleanup is performed after a test body finishes execution is to use a complete-lastly clause, syntax that is defined in trait CompleteLastly, which this trait extends. Using cleanup-lastly will ensure that cleanup will occur whether FutureOutcome-producing code completes abruptly by throwing an exception, or returns normally yielding a FutureOutcome. In the latter case, complete-lastly will register the cleanup code to execute asynchronously when the FutureOutcome completes.

    The withFixture method is designed to be stacked, and to enable this, you should always call the super implementation of withFixture, 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 a withFixture implementation that performs cleanup looks like this:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
      // Perform setup here
      complete {
        super.withFixture(test) // Invoke the test function
      } lastly {
        // Perform cleanup here
      }
    }
    

    If you have no cleanup to perform, you can write withFixture like this instead:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
      // Perform setup here
      super.withFixture(test) // Invoke the test function
    }
    

    The test function and withFixture method returns a FutureOutcome, a ScalaTest class that wraps a Scala Future[Outcome] and offers methods more specific to asynchronous test outcomes. In a Scala Future, any exception results in a scala.util.Failure. In a FutureOutcome, a thrown TestPendingException always results in a Pending, a thrown TestCanceledException always results in a Canceled, and any other exception, so long as it isn't suite-aborting, results in a Failed. This is true of the asynchronous test code itself that's represented by the FutureOutcome and any transformation or callback registered on the FutureOutcome in withFixture.

    If you want to perform an action only for certain outcomes, you'll need to register code performing that action on the FutureOutcome using one of FutureOutcome's callback registration methods:

    • onSucceededThen - executed if the Outcome is a Succeeded.
    • onFailedThen - executed if the Outcome is a Failed.
    • onCanceledThen - executed if the Outcome is a Canceled.
    • onPendingThen - executed if the Outcome is a Pending.
    • onOutcomeThen - executed on any Outcome (i.e., no suite-aborting exception is thrown).
    • onAbortedThen - executed if a suite-aborting exception is thrown.
    • onCompletedThen - executed whether the result is an Outcome or a thrown suite-aborting exception.

    For example, if you want to perform an action if a test fails, you'd register the callback using onFailedThen, like this:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      val futureOutcome = super.withFixture(test) // Invoke the test function
    
      futureOutcome onFailedThen { ex =>
        // perform action that you want to occur
        // only if a test fails here
      }
    }
    

    Note that all callback registration methods, such as onFailedThen used in the previous example, return a new FutureOutcome that won't complete until the the original FutureOutcome and the callback has completed. If the callback throws an exception, the resulting FutureOutcome will represent that exception. For example, if a FutureOutcome results in Failed, but a callback registered on that FutureOutcome with onFailedThen throws TestPendingException, the result of the FutureOutcome returned by onFailedThen will be Pending.

    Lastly, if you want to change the outcome in some way in withFixture, you'll need to use the change method of FutureOutcome, like this:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      val futureOutcome = super.withFixture(test) // Invoke the test function
    
      futureOutcome change { outcome =>
        // transform the outcome into a new outcome here
      }
    }
    

  19. trait AsyncTestSuiteMixin extends SuiteMixin

    Permalink

    Trait defining abstract "lifecycle" methods that are implemented in AsyncTestSuite and can be overridden in stackable modification traits.

    Trait defining abstract "lifecycle" methods that are implemented in AsyncTestSuite and can be overridden in stackable modification traits.

    The main use case for this trait is to override withFixture in a mixin trait. Here's an example:

    trait Builder extends AsyncTestSuiteMixin { this: AsyncTestSuite =>
    
      final val builder = new ThreadSafeStringBuilder
    
      abstract override def withFixture(test: NoArgAsyncTest) = {
        builder.append("ScalaTest is ")
        complete {
          super.withFixture(test) // To be stackable, must call super.withFixture
        } lastly {
          builder.clear()
        }
      }
    }
    

  20. abstract class AsyncWordSpec extends AsyncWordSpecLike

    Permalink

    Enables testing of asynchronous code without blocking, using a style consistent with traditional WordSpec tests.

    Enables testing of asynchronous code without blocking, using a style consistent with traditional WordSpec tests.

    Recommended Usage: AsyncFunSpec is intended to enable users of FunSpec to write non-blocking asynchronous tests that are consistent with their traditional FunSpec tests. Note: AsyncFunSpec is intended for use in special situations where non-blocking asynchronous testing is needed, with class FunSpec used for general needs.

    Given a Future returned by the code you are testing, you need not block until the Future completes before performing assertions against its value. You can instead map those assertions onto the Future and return the resulting Future[Assertion] to ScalaTest. The test will complete asynchronously, when the Future[Assertion] completes.

    Here's an example AsyncWordSpec:

    package org.scalatest.examples.asyncwordspec
    
    import org.scalatest.AsyncWordSpec
    import scala.concurrent.Future
    
    class AddSpec extends AsyncWordSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "addSoon" should {
        "eventually compute a sum of passed Ints" in {
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" should {
        "immediately compute a sum of passed Ints" in {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    it” is a method, defined in AsyncWordSpec, which will be invoked by the primary constructor of AddSpec. You specify the name of the test as a string between the parentheses, and the test code itself between curly braces. The test code is a function passed as a by-name parameter to it, which registers it for later execution. The result type of the by-name in an AsyncWordSpec must be Future[Assertion].

    In an AsyncWordSpec you write a one (or more) sentence specification for each bit of behavior you wish to specify and test. Each specification sentence has a "subject," which is sometimes called the system under test (or SUT). The subject is entity being specified and tested and also serves as the subject of the sentences you write for each test. A subject can be followed by one of three verbs, should, must, or can, and a block. Here are some examples:

    "A Stack" should {
      // ...
    }
    "An Account" must {
      // ...
    }
    "A ShippingManifest" can {
      // ...
    }
    

    You can describe a subject in varying situations by using a when clause. A when clause follows the subject and precedes a block. In the block after the when, you place strings that describe a situation or a state the subject may be in using a string, each followed by a verb. Here's an example:

    "A Stack" when {
      "empty" should {
        // ...
      }
      "non-empty" should {
        // ...
      }
      "full" should {
        // ...
      }
    }
    

    When you are ready to finish a sentence, you write a string followed by in and a block that contains the code of the test. In short, you structure an AsyncWordSpec exactly like a WordSpec, but with tests having result type Assertion or Future[Assertion]. For more examples of structure, see the documentation for WordSpec.

    Starting with version 3.0.0, ScalaTest assertions and matchers have result type Assertion. The result type of the first test in the example above, therefore, is Future[Assertion]. For clarity, here's the relevant code in a REPL session:

    scala> import org.scalatest._
    import org.scalatest._
    
    scala> import Assertions._
    import Assertions._
    
    scala> import scala.concurrent.Future
    import scala.concurrent.Future
    
    scala> import scala.concurrent.ExecutionContext
    import scala.concurrent.ExecutionContext
    
    scala> implicit val executionContext = ExecutionContext.Implicits.global
    executionContext: scala.concurrent.ExecutionContextExecutor = [email protected]
    
    scala> def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    addSoon: (addends: Int*)scala.concurrent.Future[Int]
    
    scala> val futureSum: Future[Int] = addSoon(1, 2)
    futureSum: scala.concurrent.Future[Int] = [email protected]
    
    scala> futureSum map { sum => assert(sum == 3) }
    res0: scala.concurrent.Future[org.scalatest.Assertion] = [email protected]
    

    The second test has result type Assertion:

    scala> def addNow(addends: Int*): Int = addends.sum
    addNow: (addends: Int*)Int
    
    scala> val sum: Int = addNow(1, 2)
    sum: Int = 3
    
    scala> assert(sum == 3)
    res1: org.scalatest.Assertion = Succeeded
    

    When AddSpec is constructed, the second test will be implicitly converted to Future[Assertion] and registered. The implicit conversion is from Assertion to Future[Assertion], so you must end synchronous tests in some ScalaTest assertion or matcher expression. If a test would not otherwise end in type Assertion, you can place succeed at the end of the test. succeed, a field in trait Assertions, returns the Succeeded singleton:

    scala> succeed
    res2: org.scalatest.Assertion = Succeeded
    

    Thus placing succeed at the end of a test body will satisfy the type checker:

      "immediately compute a sum of passed Ints" in {
        val sum: Int = addNow(1, 2)
        assert(sum == 3)
        println("hi") // println has result type Unit
        succeed       // succeed has result type Assertion
      }
    

    An AsyncWordSpec's lifecycle has two phases: the registration phase and the ready phase. It starts in registration phase and enters ready phase the first time run is called on it. It then remains in ready phase for the remainder of its lifetime.

    Tests can only be registered with the it method while the AsyncWordSpec is in its registration phase. Any attempt to register a test after the AsyncWordSpec has entered its ready phase, i.e., after run has been invoked on the AsyncWordSpec, will be met with a thrown TestRegistrationClosedException. The recommended style of using AsyncWordSpec is to register tests during object construction as is done in all the examples shown here. If you keep to the recommended style, you should never see a TestRegistrationClosedException.

    Asynchronous execution model

    AsyncWordSpec extends AsyncTestSuite, which provides an implicit scala.concurrent.ExecutionContext named executionContext. This execution context is used by AsyncWordSpec to transform the Future[Assertion]s returned by each test into the FutureOutcome returned by the test function passed to withFixture. This ExecutionContext is also intended to be used in the tests, including when you map assertions onto futures.

    On both the JVM and Scala.js, the default execution context provided by ScalaTest's asynchronous testing styles confines execution to a single thread per test. On JavaScript, where single-threaded execution is the only possibility, the default execution context is scala.scalajs.concurrent.JSExecutionContext.Implicits.queue. On the JVM, the default execution context is a serial execution context provided by ScalaTest itself.

    When ScalaTest's serial execution context is called upon to execute a task, that task is recorded in a queue for later execution. For example, one task that will be placed in this queue is the task that transforms the Future[Assertion] returned by an asynchronous test body to the FutureOutcome returned from the test function. Other tasks that will be queued are any transformations of, or callbacks registered on, Futures that occur in your test body, including any assertions you map onto Futures. Once the test body returns, the thread that executed the test body will execute the tasks in that queue one after another, in the order they were enqueued.

    ScalaTest provides its serial execution context as the default on the JVM for three reasons. First, most often running both tests and suites in parallel does not give a significant performance boost compared to just running suites in parallel. Thus parallel execution of Future transformations within individual tests is not generally needed for performance reasons.

    Second, if multiple threads are operating in the same suite concurrently, you'll need to make sure access to any mutable fixture objects by multiple threads is synchronized. Although access to mutable state along the same linear chain of Future transformations need not be synchronized, this does not hold true for callbacks, and in general it is easy to make a mistake. Simply put: synchronizing access to shared mutable state is difficult and error prone. Because ScalaTest's default execution context on the JVM confines execution of Future transformations and call backs to a single thread, you need not (by default) worry about synchronizing access to mutable state in your asynchronous-style tests.

    Third, asynchronous-style tests need not be complete when the test body returns, because the test body returns a Future[Assertion]. This Future[Assertion] will often represent a test that has not yet completed. As a result, when using a more traditional execution context backed by a thread-pool, you could potentially start many more tests executing concurrently than there are threads in the thread pool. The more concurrently execute tests you have competing for threads from the same limited thread pool, the more likely it will be that tests will intermitently fail due to timeouts.

    Using ScalaTest's serial execution context on the JVM will ensure the same thread that produced the Future[Assertion] returned from a test body is also used to execute any tasks given to the execution context while executing the test body—and that thread will not be allowed to do anything else until the test completes. If the serial execution context's task queue ever becomes empty while the Future[Assertion] returned by that test's body has not yet completed, the thread will block until another task for that test is enqueued. Although it may seem counter-intuitive, this blocking behavior means the total number of tests allowed to run concurrently will be limited to the total number of threads executing suites. This fact means you can tune the thread pool such that maximum performance is reached while avoiding (or at least, reducing the likelihood of) tests that fail due to timeouts because of thread competition.

    This thread confinement strategy does mean, however, that when you are using the default execution context on the JVM, you must be sure to never block in the test body waiting for a task to be completed by the execution context. If you block, your test will never complete. This kind of problem will be obvious, because the test will consistently hang every time you run it. (If a test is hanging, and you're not sure which one it is, enable slowpoke notifications.) If you really do want to block in your tests, you may wish to just use a traditional WordSpec with ScalaFutures instead. Alternatively, you could override the executionContext and use a traditional ExecutionContext backed by a thread pool. This will enable you to block in an asynchronous-style test on the JVM, but you'll need to worry about synchronizing access to shared mutable state.

    To use a different execution context, just override executionContext. For example, if you prefer to use the runNow execution context on Scala.js instead of the default queue, you would write:

    // on Scala.js
    implicit override def executionContext =
        scala.scalajs.concurrent.JSExecutionContext.Implicits.runNow
    

    If you prefer on the JVM to use the global execution context, which is backed by a thread pool, instead of ScalaTest's default serial execution contex, which confines execution to a single thread, you would write:

    // on the JVM (and also compiles on Scala.js, giving
    // you the queue execution context)
    implicit override def executionContext =
        scala.concurrent.ExecutionContext.Implicits.global
    

    Serial and parallel test execution

    By default (unless you mix in ParallelTestExecution), tests in an AsyncWordSpec will be executed one after another, i.e., serially. This is true whether those tests return Assertion or Future[Assertion], no matter what threads are involved. This default behavior allows you to re-use a shared fixture, such as an external database that needs to be cleaned after each test, in multiple tests in async-style suites. This is implemented by registering each test, other than the first test, to run as a continuation after the previous test completes.

    If you want the tests of an AsyncWordSpec to be executed in parallel, you must mix in ParallelTestExecution and enable parallel execution of tests in your build. You enable parallel execution in Runner with the -P command line flag. In the ScalaTest Maven Plugin, set parallel to true. In sbt, parallel execution is the default, but to be explicit you can write:

    parallelExecution in Test := true // the default in sbt
    

    On the JVM, if both ParallelTestExecution is mixed in and parallel execution is enabled in the build, tests in an async-style suite will be started in parallel, using threads from the Distributor, and allowed to complete in parallel, using threads from the executionContext. If you are using ScalaTest's serial execution context, the JVM default, asynchronous tests will run in parallel very much like traditional (such as WordSpec) tests run in parallel: 1) Because ParallelTestExecution extends OneInstancePerTest, each test will run in its own instance of the test class, you need not worry about synchronizing access to mutable instance state shared by different tests in the same suite. 2) Because the serial execution context will confine the execution of each test to the single thread that executes the test body, you need not worry about synchronizing access to shared mutable state accessed by transformations and callbacks of Futures inside the test.

    If ParallelTestExecution is mixed in but parallel execution of suites is not enabled, asynchronous tests on the JVM will be started sequentially, by the single thread that invoked run, but without waiting for one test to complete before the next test is started. As a result, asynchronous tests will be allowed to complete in parallel, using threads from the executionContext. If you are using the serial execution context, however, you'll see the same behavior you see when parallel execution is disabled and a traditional suite that mixes in ParallelTestExecution is executed: the tests will run sequentially. If you use an execution context backed by a thread-pool, such as global, however, even though tests will be started sequentially by one thread, they will be allowed to run concurrently using threads from the execution context's thread pool.

    The latter behavior is essentially what you'll see on Scala.js when you execute a suite that mixes in ParallelTestExecution. Because only one thread exists when running under JavaScript, you can't "enable parallel execution of suites." However, it may still be useful to run tests in parallel on Scala.js, because tests can invoke API calls that are truly asynchronous by calling into external APIs that take advantage of non-JavaScript threads. Thus on Scala.js, ParallelTestExecution allows asynchronous tests to run in parallel, even though they must be started sequentially. This may give you better performance when you are using API calls in your Scala.js tests that are truly asynchronous.

    Futures and expected exceptions

    If you need to test for expected exceptions in the context of futures, you can use the recoverToSucceededIf and recoverToExceptionIf methods of trait RecoverMethods. Because this trait is mixed into supertrait AsyncTestSuite, both of these methods are available by default in an AsyncWordSpec.

    If you just want to ensure that a future fails with a particular exception type, and do not need to inspect the exception further, use recoverToSucceededIf:

    recoverToSucceededIf[IllegalStateException] { // Result type: Future[Assertion]
      emptyStackActor ? Peek
    }
    

    The recoverToSucceededIf method performs a job similar to assertThrows, except in the context of a future. It transforms a Future of any type into a Future[Assertion] that succeeds only if the original future fails with the specified exception. Here's an example in the REPL:

    scala> import org.scalatest.RecoverMethods._
    import org.scalatest.RecoverMethods._
    
    scala> import scala.concurrent.Future
    import scala.concurrent.Future
    
    scala> import scala.concurrent.ExecutionContext.Implicits.global
    import scala.concurrent.ExecutionContext.Implicits.global
    
    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { throw new IllegalStateException }
         | }
    res0: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res0.value
    res1: Option[scala.util.Try[org.scalatest.Assertion]] = Some(Success(Succeeded))
    

    Otherwise it fails with an error message similar to those given by assertThrows:

    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { throw new RuntimeException }
         | }
    res2: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res2.value
    res3: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: Expected exception
          java.lang.IllegalStateException to be thrown, but java.lang.RuntimeException
          was thrown))
    
    scala> recoverToSucceededIf[IllegalStateException] {
         |   Future { 42 }
         | }
    res4: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res4.value
    res5: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: Expected exception
          java.lang.IllegalStateException to be thrown, but no exception was thrown))
    

    The recoverToExceptionIf method differs from the recoverToSucceededIf in its behavior when the assertion succeeds: recoverToSucceededIf yields a Future[Assertion], whereas recoverToExceptionIf yields a Future[T], where T is the expected exception type.

    recoverToExceptionIf[IllegalStateException] { // Result type: Future[IllegalStateException]
      emptyStackActor ? Peek
    }
    

    In other words, recoverToExpectionIf is to intercept as recovertToSucceededIf is to assertThrows. The first one allows you to perform further assertions on the expected exception. The second one gives you a result type that will satisfy the type checker at the end of the test body. Here's an example showing recoverToExceptionIf in the REPL:

    scala> val futureEx =
         |   recoverToExceptionIf[IllegalStateException] {
         |     Future { throw new IllegalStateException("hello") }
         |   }
    futureEx: scala.concurrent.Future[IllegalStateException] = ...
    
    scala> futureEx.value
    res6: Option[scala.util.Try[IllegalStateException]] =
        Some(Success(java.lang.IllegalStateException: hello))
    
    scala> futureEx map { ex => assert(ex.getMessage == "world") }
    res7: scala.concurrent.Future[org.scalatest.Assertion] = ...
    
    scala> res7.value
    res8: Option[scala.util.Try[org.scalatest.Assertion]] =
        Some(Failure(org.scalatest.exceptions.TestFailedException: "[hello]" did not equal "[world]"))
    

    Ignored tests

    To support the common use case of temporarily disabling a test, with the good intention of resurrecting the test at a later time, AsyncWordSpec adds a method ignore to strings that can be used instead of in to register a test. For example, to temporarily disable the test with the name "A Stack should pop values in last-in-first-out order", just change “in” into “ignore,” like this:

    package org.scalatest.examples.asyncwordspec.ignore
    
    import org.scalatest.AsyncWordSpec
    import scala.concurrent.Future
    
    class AddSpec extends AsyncWordSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "addSoon" should {
        "eventually compute a sum of passed Ints" ignore {
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" should {
        "immediately compute a sum of passed Ints" in {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    If you run this version of AddSpec with:

    scala> org.scalatest.run(new AddSpec)
    

    It will run only the second test and report that the first test was ignored:

    AddSpec:
    addSoon
    - should eventually compute a sum of passed Ints !!! IGNORED !!!
    addNow
    - should immediately compute a sum of passed Ints
    

    If you wish to temporarily ignore an entire suite of tests, you can (on the JVM, not Scala.js) annotate the test class with @Ignore, like this:

    package org.scalatest.examples.asyncwordspec.ignoreall
    
    import org.scalatest.AsyncWordSpec
    import scala.concurrent.Future
    import org.scalatest.Ignore
    
    @Ignore
    class AddSpec extends AsyncWordSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "addSoon" should {
        "eventually compute a sum of passed Ints" in {
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" should {
        "immediately compute a sum of passed Ints" in {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    When you mark a test class with a tag annotation, ScalaTest will mark each test defined in that class with that tag. Thus, marking the AddSpec in the above example with the @Ignore tag annotation means that both tests in the class will be ignored. If you run the above AddSpec in the Scala interpreter, you'll see:

    AddSpec:
    addSoon
    - should eventually compute a sum of passed Ints !!! IGNORED !!!
    addNow
    - should immediately compute a sum of passed Ints !!! IGNORED !!!
    

    Note that marking a test class as ignored won't prevent it from being discovered by ScalaTest. Ignored classes will be discovered and run, and all their tests will be reported as ignored. This is intended to keep the ignored class visible, to encourage the developers to eventually fix and “un-ignore” it. If you want to prevent a class from being discovered at all (on the JVM, not Scala.js), use the DoNotDiscover annotation instead.

    If you want to ignore all tests of a suite on Scala.js, where annotations can't be inspected at runtime, you'll need to change it to ignore at each test site. To make a suite non-discoverable on Scala.js, ensure it does not declare a public no-arg constructor. You can either declare a public constructor that takes one or more arguments, or make the no-arg constructor non-public. Because this technique will also make the suite non-discoverable on the JVM, it is a good approach for suites you want to run (but not be discoverable) on both Scala.js and the JVM.

    Informers

    One of the parameters to AsyncWordSpec's run method is a Reporter, which will collect and report information about the running suite of tests. Information about suites and tests that were run, whether tests succeeded or failed, and tests that were ignored will be passed to the Reporter as the suite runs. Most often the reporting done by default by AsyncWordSpec's methods will be sufficient, but occasionally you may wish to provide custom information to the Reporter from a test. For this purpose, an Informer that will forward information to the current Reporter is provided via the info parameterless method. You can pass the extra information to the Informer via its apply method. The Informer will then pass the information to the Reporter via an InfoProvided event.

    One use case for the Informer is to pass more information about a specification to the reporter. For example, the GivenWhenThen trait provides methods that use the implicit info provided by AsyncWordSpec to pass such information to the reporter. Here's an example:

    package org.scalatest.examples.asyncwordspec.info
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends AsyncWordSpec with GivenWhenThen {
    
      "A mutable Set" should {
        "allow an element to be added" in {
          Given("an empty mutable Set")
          val set = mutable.Set.empty[String]
    
          When("an element is added")
          set += "clarity"
    
          Then("the Set should have size 1")
          assert(set.size === 1)
    
          And("the Set should contain the added element")
          assert(set.contains("clarity"))
    
          info("That's all folks!")
          succeed
        }
      }
    }
    

    If you run this AsyncWordSpec from the interpreter, you will see the following output:

    scala> org.scalatest.run(new SetSpec)
    A mutable Set
    - should allow an element to be added
      + Given an empty mutable Set
      + When an element is added
      + Then the Set should have size 1
      + And the Set should contain the added element
      + That's all folks!
    

    Documenters

    AsyncWordSpec also provides a markup method that returns a Documenter, which allows you to send to the Reporter text formatted in Markdown syntax. You can pass the extra information to the Documenter via its apply method. The Documenter will then pass the information to the Reporter via an MarkupProvided event.

    Here's an example AsyncWordSpec that uses markup:

    package org.scalatest.examples.asyncwordspec.markup
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends AsyncWordSpec with GivenWhenThen {
    
      markup { """
    
    Mutable Set
    -----------
    
    A set is a collection that contains no duplicate elements.
    
    To implement a concrete mutable set, you need to provide implementations
    of the following methods:
    
        def contains(elem: A): Boolean
        def iterator: Iterator[A]
        def += (elem: A): this.type
        def -= (elem: A): this.type
    
    If you wish that methods like `take`,
    `drop`, `filter` return the same kind of set,
    you should also override:
    
        def empty: This
    
    It is also good idea to override methods `foreach` and
    `size` for efficiency.
    
      """ }
    
      "A mutable Set" should {
        "allow an element to be added" in {
          Given("an empty mutable Set")
          val set = mutable.Set.empty[String]
    
          When("an element is added")
          set += "clarity"
    
          Then("the Set should have size 1")
          assert(set.size === 1)
    
          And("the Set should contain the added element")
          assert(set.contains("clarity"))
    
          markup("This test finished with a **bold** statement!")
          succeed
        }
      }
    }
    

    Although all of ScalaTest's built-in reporters will display the markup text in some form, the HTML reporter will format the markup information into HTML. Thus, the main purpose of markup is to add nicely formatted text to HTML reports. Here's what the above SetSpec would look like in the HTML reporter:

    Notifiers and alerters

    ScalaTest records text passed to info and markup during tests, and sends the recorded text in the recordedEvents field of test completion events like TestSucceeded and TestFailed. This allows string reporters (like the standard out reporter) to show info and markup text after the test name in a color determined by the outcome of the test. For example, if the test fails, string reporters will show the info and markup text in red. If a test succeeds, string reporters will show the info and markup text in green. While this approach helps the readability of reports, it means that you can't use info to get status updates from long running tests.

    To get immediate (i.e., non-recorded) notifications from tests, you can use note (a Notifier) and alert (an Alerter). Here's an example showing the differences:

    package org.scalatest.examples.asyncwordspec.note
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends AsyncWordSpec {
    
      "A mutable Set" should {
        "allow an element to be added" in {
    
          info("info is recorded")
          markup("markup is *also* recorded")
          note("notes are sent immediately")
          alert("alerts are also sent immediately")
    
          val set = mutable.Set.empty[String]
          set += "clarity"
          assert(set.size === 1)
          assert(set.contains("clarity"))
        }
      }
    }
    

    Because note and alert information is sent immediately, it will appear before the test name in string reporters, and its color will be unrelated to the ultimate outcome of the test: note text will always appear in green, alert text will always appear in yellow. Here's an example:

    scala> org.scalatest.run(new SetSpec)
    SetSpec:
    A mutable Set
      + notes are sent immediately
      + alerts are also sent immediately
    - should allow an element to be added
      + info is recorded
      + markup is *also* recorded
    

    Another example is slowpoke notifications. If you find a test is taking a long time to complete, but you're not sure which test, you can enable slowpoke notifications. ScalaTest will use an Alerter to fire an event whenever a test has been running longer than a specified amount of time.

    In summary, use info and markup for text that should form part of the specification output. Use note and alert to send status notifications. (Because the HTML reporter is intended to produce a readable, printable specification, info and markup text will appear in the HTML report, but note and alert text will not.)

    Pending tests

    A pending test is one that has been given a name but is not yet implemented. The purpose of pending tests is to facilitate a style of testing in which documentation of behavior is sketched out before tests are written to verify that behavior (and often, before the behavior of the system being tested is itself implemented). Such sketches form a kind of specification of what tests and functionality to implement later.

    To support this style of testing, a test can be given a name that specifies one bit of behavior required by the system being tested. At the end of the test, it can call method pending, which will cause it to complete abruptly with TestPendingException.

    Because tests in ScalaTest can be designated as pending with TestPendingException, both the test name and any information sent to the reporter when running the test can appear in the report of a test run. (In other words, the code of a pending test is executed just like any other test.) However, because the test completes abruptly with TestPendingException, the test will be reported as pending, to indicate the actual test, and possibly the functionality, has not yet been implemented. Here's an example:

    package org.scalatest.examples.asyncwordspec.pending
    
    import org.scalatest.AsyncWordSpec
    import scala.concurrent.Future
    
    class AddSpec extends AsyncWordSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "addSoon" should {
        "eventually compute a sum of passed Ints" in (pending)
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" should {
        "immediately compute a sum of passed Ints" in {
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    (Note: "(pending)" is the body of the test. Thus the test contains just one statement, an invocation of the pending method, which throws TestPendingException.) If you run this version of AddSpec with:

    scala> org.scalatest.run(new AddSpec)
    

    It will run both tests, but report that first test is pending. You'll see:

    AddSpec:
    addSoon
    - should eventually compute a sum of passed Ints (pending)
    addNow
    - should immediately compute a sum of passed Ints
    

    One difference between an ignored test and a pending one is that an ignored test is intended to be used during significant refactorings of the code under test, when tests break and you don't want to spend the time to fix all of them immediately. You can mark some of those broken tests as ignored temporarily, so that you can focus the red bar on just failing tests you actually want to fix immediately. Later you can go back and fix the ignored tests. In other words, by ignoring some failing tests temporarily, you can more easily notice failed tests that you actually want to fix. By contrast, a pending test is intended to be used before a test and/or the code under test is written. Pending indicates you've decided to write a test for a bit of behavior, but either you haven't written the test yet, or have only written part of it, or perhaps you've written the test but don't want to implement the behavior it tests until after you've implemented a different bit of behavior you realized you need first. Thus ignored tests are designed to facilitate refactoring of existing code whereas pending tests are designed to facilitate the creation of new code.

    One other difference between ignored and pending tests is that ignored tests are implemented as a test tag that is excluded by default. Thus an ignored test is never executed. By contrast, a pending test is implemented as a test that throws TestPendingException (which is what calling the pending method does). Thus the body of pending tests are executed up until they throw TestPendingException.

    Tagging tests

    An AsyncFunSpec's tests may be classified into groups by tagging them with string names. As with any suite, when executing an AsyncFunSpec, groups of tests can optionally be included and/or excluded. To tag an AsyncFunSpec's tests, you pass objects that extend class org.scalatest.Tag to methods that register tests. Class Tag takes one parameter, a string name. If you have created tag annotation interfaces as described in the Tag documentation, then you will probably want to use tag names on your test functions that match. To do so, simply pass the fully qualified names of the tag interfaces to the Tag constructor. For example, if you've defined a tag annotation interface with fully qualified name, com.mycompany.tags.DbTest, then you could create a matching tag for AsyncFunSpecs like this:

    package org.scalatest.examples.asyncwordspec.tagging
    
    import org.scalatest.Tag
    
    object DbTest extends Tag("com.mycompany.tags.DbTest")
    

    Given these definitions, you could place AsyncFunSpec tests into groups with tags like this:

    import org.scalatest.AsyncWordSpec
    import org.scalatest.tagobjects.Slow
    import scala.concurrent.Future
    
    class AddSpec extends AsyncWordSpec {
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "addSoon" should {
        "eventually compute a sum of passed Ints" taggedAs(Slow) in {
          val futureSum: Future[Int] = addSoon(1, 2)
          // You can map assertions onto a Future, then return
          // the resulting Future[Assertion] to ScalaTest:
          futureSum map { sum => assert(sum == 3) }
        }
      }
    
      def addNow(addends: Int*): Int = addends.sum
    
      "addNow" should {
        "immediately compute a sum of passed Ints" taggedAs(Slow, DbTest) in {
    
          val sum: Int = addNow(1, 2)
          // You can also write synchronous tests. The body
          // must have result type Assertion:
          assert(sum == 3)
        }
      }
    }
    

    This code marks both tests with the org.scalatest.tags.Slow tag, and the second test with the com.mycompany.tags.DbTest tag.

    The run method takes a Filter, whose constructor takes an optional Set[String] called tagsToInclude and a Set[String] called tagsToExclude. If tagsToInclude is None, all tests will be run except those those belonging to tags listed in the tagsToExclude Set. If tagsToInclude is defined, only tests belonging to tags mentioned in the tagsToInclude set, and not mentioned in tagsToExclude, will be run.

    It is recommended, though not required, that you create a corresponding tag annotation when you create a Tag object. A tag annotation (on the JVM, not Scala.js) allows you to tag all the tests of an AsyncFunSpec in one stroke by annotating the class. For more information and examples, see the documentation for class Tag. On Scala.js, to tag all tests of a suite, you'll need to tag each test individually at the test site.

    Shared fixtures

    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.

    ScalaTest recommends three techniques to eliminate such code duplication in async styles:

    • Refactor using Scala
    • Override withFixture
    • Mix in a before-and-after trait

    Each technique is geared towards helping you reduce code duplication without introducing instance vars, shared mutable objects, or other dependencies between tests. Eliminating shared mutable state across tests will make your test code easier to reason about and eliminate the need to synchronize access to shared mutable state on the JVM.

    The following sections describe these techniques, including explaining the recommended usage for each. But first, here's a table summarizing the options:

    Refactor using Scala when different tests need different fixtures.
    get-fixture methods The extract method refactor helps you create a fresh instances of mutable fixture objects in each test that needs them, but doesn't help you clean them up when you're done.
    loan-fixture methods Factor out dupicate code with the loan pattern when different tests need different fixtures that must be cleaned up afterwards.
    Override withFixture when most or all tests need the same fixture.
    withFixture(NoArgAsyncTest) The recommended default approach when most or all tests need the same fixture treatment. This general technique allows you, for example, to perform side effects at the beginning and end of all or most tests, transform the outcome of tests, retry tests, make decisions based on test names, tags, or other test data. Use this technique unless:
    Different tests need different fixtures (refactor using Scala instead)
    An exception in fixture code should abort the suite, not fail the test (use a before-and-after trait instead)
    You have objects to pass into tests (override withFixture(OneArgAsyncTest) instead)
    withFixture(OneArgAsyncTest) Use when you want to pass the same fixture object or objects as a parameter into all or most tests.
    Mix in a before-and-after trait when you want an aborted suite, not a failed test, if the fixture code fails.
    BeforeAndAfter Use this boilerplate-buster when you need to perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.
    BeforeAndAfterEach Use when you want to stack traits that perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.

    Calling get-fixture methods

    If you need to create the same mutable fixture objects in multiple tests, and don't need to clean them up after using them, the simplest approach is to write one or more get-fixture methods. A get-fixture method returns a new instance of a needed fixture object (or a holder object containing multiple fixture objects) each time it is called. You can call a get-fixture method at the beginning of each test that needs the fixture, storing the returned object or objects in local variables. Here's an example:

    package org.scalatest.examples.asyncwordspec.getfixture
    
    import org.scalatest.AsyncWordSpec
    import scala.concurrent.Future
    
    class ExampleSpec extends AsyncWordSpec {
    
      def fixture: Future[String] = Future { "ScalaTest is " }
    
      "Testing" should {
        "be easy" in {
          val future = fixture
          val result = future map { s => s + "easy!" }
          result map { s =>
            assert(s == "ScalaTest is easy!")
          }
        }
    
        "be fun" in {
          val future = fixture
          val result = future map { s => s + "fun!" }
          result map { s =>
            assert(s == "ScalaTest is fun!")
          }
        }
      }
    }
    

    If you need to configure fixture objects differently in different tests, you can pass configuration into the get-fixture method. For example, you could pass in an initial value for a fixture object as a parameter to the get-fixture method.

    Overriding withFixture(NoArgAsyncTest)

    Although the get-fixture method approach takes care of setting up a fixture at the beginning of each test, it doesn't address the problem of cleaning up a fixture at the end of the test. If you just need to perform a side-effect at the beginning or end of a test, and don't need to actually pass any fixture objects into the test, you can override withFixture(NoArgAsyncTest), a method defined in trait AsyncTestSuite, a supertrait of AsyncFunSpec.

    Trait AsyncFunSpec's runTest method passes a no-arg async test function to withFixture(NoArgAsyncTest). It is withFixture's responsibility to invoke that test function. The default implementation of withFixture simply invokes the function and returns the result, like this:

    // Default implementation in trait AsyncTestSuite
    protected def withFixture(test: NoArgAsyncTest): FutureOutcome = {
      test()
    }
    

    You can, therefore, override withFixture to perform setup before invoking the test function, and/or perform cleanup after the test completes. The recommended way to ensure cleanup is performed after a test completes is to use the complete-lastly syntax, defined in supertrait CompleteLastly. The complete-lastly syntax will ensure that cleanup will occur whether future-producing code completes abruptly by throwing an exception, or returns normally yielding a future. In the latter case, complete-lastly will register the cleanup code to execute asynchronously when the future completes.

    The withFixture method is designed to be stacked, and to enable this, you should always call the super implementation of withFixture, 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)”, like this:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      complete {
        super.withFixture(test) // Invoke the test function
      } lastly {
        // Perform cleanup here
      }
    }
    

    If you have no cleanup to perform, you can write withFixture like this instead:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      super.withFixture(test) // Invoke the test function
    }
    

    If you want to perform an action only for certain outcomes, you'll need to register code performing that action as a callback on the Future using one of Future's registration methods: onComplete, onSuccess, or onFailure. Note that if a test fails, that will be treated as a scala.util.Success(org.scalatest.Failed). So if you want to perform an action if a test fails, for example, you'd register the callback using onSuccess.

    Here's an example in which withFixture(NoArgAsyncTest) is used to take a snapshot of the working directory if a test fails, and send that information to the standard output stream:

    package org.scalatest.examples.asyncwordspec.noargasynctest
    
    import java.io.File
    import org.scalatest._
    import scala.concurrent.Future
    
    class ExampleSpec extends AsyncWordSpec {
    
      override def withFixture(test: NoArgAsyncTest) = {
    
        super.withFixture(test) onFailedThen { _ =>
          val currDir = new File(".")
          val fileNames = currDir.list()
          info("Dir snapshot: " + fileNames.mkString(", "))
        }
      }
    
      def addSoon(addends: Int*): Future[Int] = Future { addends.sum }
    
      "This test" should {
        "succeed" in {
          addSoon(1, 1) map { sum => assert(sum == 2) }
        }
    
        "fail" in {
          addSoon(1, 1) map { sum => assert(sum == 3) }
        }
      }
    }
    

    Running this version of ExampleSpec in the interpreter in a directory with two files, hello.txt and world.txt would give the following output:

    scala> org.scalatest.run(new ExampleSpec)
    ExampleSpec:
    This test
    - should succeed
    - should fail *** FAILED ***
      2 did not equal 3 (:33)
    

    Note that the NoArgAsyncTest passed to withFixture, in addition to an apply method that executes the test, also includes the test name and the config map passed to runTest. Thus you can also use the test name and configuration objects in your withFixture implementation.

    Lastly, if you want to transform the outcome in some way in withFixture, you'll need to use either the map or transform methods of Future, like this:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      val futureOutcome = super.withFixture(test) // Invoke the test function
    
      futureOutcome change { outcome =>
        // transform the outcome into a new outcome here
      }
    }
    

    Note that a NoArgAsyncTest's apply method will return a scala.util.Failure only if the test completes abruptly with a "test-fatal" exception (such as OutOfMemoryError) that should cause the suite to abort rather than the test to fail. Thus usually you would use map to transform future outcomes, not transform, so that such test-fatal exceptions pass through unchanged. The suite will abort asynchronously with any exception returned from NoArgAsyncTest's apply method in a scala.util.Failure.

    Calling loan-fixture methods

    If you need to both pass a fixture object into a test and perform cleanup at the end of the test, you'll need to use the loan pattern. If different tests need different fixtures that require cleanup, you can implement the loan pattern directly by writing loan-fixture methods. A loan-fixture method takes a function whose body forms part or all of a test's code. It creates a fixture, passes it to the test code by invoking the function, then cleans up the fixture after the function returns.

    The following example shows three tests that use two fixtures, a database and a file. Both require cleanup after, so each is provided via a loan-fixture method. (In this example, the database is simulated with a StringBuffer.)

    package org.scalatest.examples.asyncwordspec.loanfixture
    
    import java.util.concurrent.ConcurrentHashMap
    
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    object DbServer { // Simulating a database server
      type Db = StringBuffer
      private final val databases = new ConcurrentHashMap[String, Db]
      def createDb(name: String): Db = {
        val db = new StringBuffer // java.lang.StringBuffer is thread-safe
        databases.put(name, db)
        db
      }
      def removeDb(name: String): Unit = {
        databases.remove(name)
      }
    }
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    import org.scalatest._
    import DbServer._
    import java.util.UUID.randomUUID
    
    class ExampleSpec extends AsyncWordSpec {
    
      def withDatabase(testCode: Future[Db] => Future[Assertion]) = {
        val dbName = randomUUID.toString // generate a unique db name
        val futureDb = Future { createDb(dbName) } // create the fixture
        complete {
          val futurePopulatedDb =
            futureDb map { db =>
              db.append("ScalaTest is ") // perform setup
            }
          testCode(futurePopulatedDb) // "loan" the fixture to the test code
        } lastly {
          removeDb(dbName) // ensure the fixture will be cleaned up
        }
      }
    
      def withActor(testCode: StringActor => Future[Assertion]) = {
        val actor = new StringActor
        complete {
          actor ! Append("ScalaTest is ") // set up the fixture
          testCode(actor) // "loan" the fixture to the test code
        } lastly {
          actor ! Clear // ensure the fixture will be cleaned up
        }
      }
    
      "Testing" should {
        // This test needs the actor fixture
        "be productive" in {
          withActor { actor =>
            actor ! Append("productive!")
            val futureString = actor ? GetValue
            futureString map { s =>
              assert(s == "ScalaTest is productive!")
            }
          }
        }
      }
    
      "Test code" should {
        // This test needs the database fixture
        "be readable" in {
          withDatabase { futureDb =>
            futureDb map { db =>
              db.append("readable!")
              assert(db.toString == "ScalaTest is readable!")
            }
          }
        }
    
        // This test needs both the actor and the database
        "be clear and concise" in {
          withDatabase { futureDb =>
            withActor { actor => // loan-fixture methods compose
              actor ! Append("concise!")
              val futureString = actor ? GetValue
              val futurePair: Future[(Db, String)] =
                futureDb zip futureString
              futurePair map { case (db, s) =>
                db.append("clear!")
                assert(db.toString == "ScalaTest is clear!")
                assert(s == "ScalaTest is concise!")
              }
            }
          }
        }
      }
    }
    

    As demonstrated by the last test, loan-fixture methods compose. Not only do loan-fixture methods allow you to give each test the fixture it needs, they allow you to give a test multiple fixtures and clean everything up afterwards.

    Also demonstrated in this example is the technique of giving each test its own "fixture sandbox" to play in. When your fixtures involve external side-effects, like creating databases, it is a good idea to give each database a unique name as is done in this example. This keeps tests completely isolated, allowing you to run them in parallel if desired.

    Overriding withFixture(OneArgTest)

    If all or most tests need the same fixture, you can avoid some of the boilerplate of the loan-fixture method approach by using a fixture.AsyncTestSuite and overriding withFixture(OneArgAsyncTest). Each test in a fixture.AsyncTestSuite takes a fixture as a parameter, allowing you to pass the fixture into the test. You must indicate the type of the fixture parameter by specifying FixtureParam, and implement a withFixture method that takes a OneArgAsyncTest. This withFixture method is responsible for invoking the one-arg async test function, so you can perform fixture set up before invoking and passing the fixture into the test function, and ensure clean up is performed after the test completes.

    To enable the stacking of traits that define withFixture(NoArgAsyncTest), it is a good idea to let withFixture(NoArgAsyncTest) invoke the test function instead of invoking the test function directly. To do so, you'll need to convert the OneArgAsyncTest to a NoArgAsyncTest. You can do that by passing the fixture object to the toNoArgAsyncTest method of OneArgAsyncTest. In other words, instead of writing “test(theFixture)”, you'd delegate responsibility for invoking the test function to the withFixture(NoArgAsyncTest) method of the same instance by writing:

    withFixture(test.toNoArgAsyncTest(theFixture))
    

    Here's a complete example:

    package org.scalatest.examples.asyncwordspec.oneargasynctest
    
    import org.scalatest._
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class ExampleSpec extends fixture.AsyncWordSpec {
    
      type FixtureParam = StringActor
    
      def withFixture(test: OneArgAsyncTest): FutureOutcome = {
    
        val actor = new StringActor
        complete {
          actor ! Append("ScalaTest is ") // set up the fixture
          withFixture(test.toNoArgAsyncTest(actor))
        } lastly {
          actor ! Clear // ensure the fixture will be cleaned up
        }
      }
    
      "Testing" should {
        "be easy" in { actor =>
          actor ! Append("easy!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is easy!")
          }
        }
    
        "be fun" in { actor =>
          actor ! Append("fun!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is fun!")
          }
        }
      }
    }
    

    In this example, the tests required one fixture object, a StringActor. If your tests need multiple fixture objects, you can simply define the FixtureParam type to be a tuple containing the objects or, alternatively, a case class containing the objects. For more information on the withFixture(OneArgAsyncTest) technique, see the documentation for fixture.AsyncFunSpec.

    Mixing in BeforeAndAfter

    In all the shared fixture examples shown so far, the activities of creating, setting up, and cleaning up the fixture objects have been performed during the test. This means that if an exception occurs during any of these activities, it will be reported as a test failure. Sometimes, however, you may want setup to happen before the test starts, and cleanup after the test has completed, so that if an exception occurs during setup or cleanup, the entire suite aborts and no more tests are attempted. The simplest way to accomplish this in ScalaTest is to mix in trait BeforeAndAfter. With this trait you can denote a bit of code to run before each test with before and/or after each test each test with after, like this:

    package org.scalatest.examples.asyncwordspec.beforeandafter
    
    import org.scalatest.AsyncWordSpec
    import org.scalatest.BeforeAndAfter
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class ExampleSpec extends AsyncWordSpec with BeforeAndAfter {
    
      final val actor = new StringActor
    
      before {
        actor ! Append("ScalaTest is ") // set up the fixture
      }
    
      after {
        actor ! Clear // clean up the fixture
      }
    
      "Testing" should {
        "be easy" in {
          actor ! Append("easy!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is easy!")
          }
        }
    
        "be fun" in {
          actor ! Append("fun!")
          val futureString = actor ? GetValue
          futureString map { s =>
            assert(s == "ScalaTest is fun!")
          }
        }
      }
    }
    

    Note that the only way before and after code can communicate with test code is via some side-effecting mechanism, commonly by reassigning instance vars or by changing the state of mutable objects held from instance vals (as in this example). If using instance vars or mutable objects held from instance vals you wouldn't be able to run tests in parallel in the same instance of the test class (on the JVM, not Scala.js) unless you synchronized access to the shared, mutable state.

    Note that on the JVM, if you override ScalaTest's default serial execution context, you will likely need to worry about synchronizing access to shared mutable fixture state, because the execution context may assign different threads to process different Future transformations. Although access to mutable state along the same linear chain of Future transformations need not be synchronized, it can be difficult to spot cases where these constraints are violated. The best approach is to use only immutable objects when transforming Futures. When that's not practical, involve only thread-safe mutable objects, as is done in the above example. On Scala.js, by contrast, you need not worry about thread synchronization, because in effect only one thread exists.

    Although BeforeAndAfter provides a minimal-boilerplate way to execute code before and after tests, it isn't designed to enable stackable traits, because the order of execution would be non-obvious. If you want to factor out before and after code that is common to multiple test suites, you should use trait BeforeAndAfterEach instead, as shown later in the next section, composing fixtures by stacking traits.

    Composing fixtures by stacking traits

    In larger projects, teams often end up with several different fixtures that test classes need in different combinations, and possibly initialized (and cleaned up) in different orders. A good way to accomplish this in ScalaTest is to factor the individual fixtures into traits that can be composed using the stackable trait pattern. This can be done, for example, by placing withFixture methods in several traits, each of which call super.withFixture. Here's an example in which the StringBuilderActor and StringBufferActor fixtures used in the previous examples have been factored out into two stackable fixture traits named Builder and Buffer:

    package org.scalatest.examples.asyncwordspec.composingwithasyncfixture
    
    import org.scalatest._
    import org.scalatest.SuiteMixin
    import collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringBuilderActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class StringBufferActor {
      private final val buf = ListBuffer.empty[String]
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => buf += value
            case Clear => buf.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[List[String]] =
        Future {
          synchronized { buf.toList }
        }
    }
    
    trait Builder extends AsyncTestSuiteMixin { this: AsyncTestSuite =>
    
      final val builderActor = new StringBuilderActor
    
      abstract override def withFixture(test: NoArgAsyncTest) = {
        builderActor ! Append("ScalaTest is ")
        complete {
          super.withFixture(test) // To be stackable, must call super.withFixture
        } lastly {
          builderActor ! Clear
        }
      }
    }
    
    trait Buffer extends AsyncTestSuiteMixin { this: AsyncTestSuite =>
    
      final val bufferActor = new StringBufferActor
    
      abstract override def withFixture(test: NoArgAsyncTest) = {
        complete {
          super.withFixture(test) // To be stackable, must call super.withFixture
        } lastly {
          bufferActor ! Clear
        }
      }
    }
    
    class ExampleSpec extends AsyncWordSpec with Builder with Buffer {
    
      "Testing" should {
        "be easy" in {
          builderActor ! Append("easy!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is easy!")
            assert(lst.isEmpty)
            bufferActor ! Append("sweet")
            succeed
          }
        }
    
        "be fun" in {
          builderActor ! Append("fun!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is fun!")
            assert(lst.isEmpty)
            bufferActor ! Append("awesome")
            succeed
          }
        }
      }
    }
    

    By mixing in both the Builder and Buffer traits, ExampleSpec gets both fixtures, which will be initialized before each test and cleaned up after. The order the traits are mixed together determines the order of execution. In this case, Builder is “super” to Buffer. If you wanted Buffer to be “super” to Builder, you need only switch the order you mix them together, like this:

    class Example2Spec extends AsyncWordSpec with Buffer with Builder
    

    If you only need one fixture you mix in only that trait:

    class Example3Spec extends AsyncWordSpec with Builder
    

    Another way to create stackable fixture traits is by extending the BeforeAndAfterEach and/or BeforeAndAfterAll traits. BeforeAndAfterEach has 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). Similarly, BeforeAndAfterAll has a beforeAll method that will be run before all tests, and an afterAll method that will be run after all tests. Here's what the previously shown example would look like if it were rewritten to use the BeforeAndAfterEach methods instead of withFixture:

    package org.scalatest.examples.asyncwordspec.composingbeforeandaftereach
    
    import org.scalatest._
    import org.scalatest.BeforeAndAfterEach
    import collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Defining actor messages
    sealed abstract class StringOp
    case object Clear extends StringOp
    case class Append(value: String) extends StringOp
    case object GetValue
    
    class StringBuilderActor { // Simulating an actor
      private final val sb = new StringBuilder
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => sb.append(value)
            case Clear => sb.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[String] =
        Future {
          synchronized { sb.toString }
        }
    }
    
    class StringBufferActor {
      private final val buf = ListBuffer.empty[String]
      def !(op: StringOp): Unit =
        synchronized {
          op match {
            case Append(value) => buf += value
            case Clear => buf.clear()
          }
        }
      def ?(get: GetValue.type)(implicit c: ExecutionContext): Future[List[String]] =
        Future {
          synchronized { buf.toList }
        }
    }
    
    trait Builder extends BeforeAndAfterEach { this: Suite =>
    
      final val builderActor = new StringBuilderActor
    
      override def beforeEach() {
        builderActor ! 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 builderActor ! Clear
      }
    }
    
    trait Buffer extends BeforeAndAfterEach { this: Suite =>
    
      final val bufferActor = new StringBufferActor
    
      override def afterEach() {
        try super.afterEach() // To be stackable, must call super.afterEach
        finally bufferActor ! Clear
      }
    }
    
    class ExampleSpec extends AsyncWordSpec with Builder with Buffer {
    
      "Testing" should {
    
        "be easy" in {
          builderActor ! Append("easy!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is easy!")
            assert(lst.isEmpty)
            bufferActor ! Append("sweet")
            succeed
          }
        }
    
        "be fun" in {
          builderActor ! Append("fun!")
          val futureString = builderActor ? GetValue
          val futureList = bufferActor ? GetValue
          val futurePair: Future[(String, List[String])] = futureString zip futureList
          futurePair map { case (str, lst) =>
            assert(str == "ScalaTest is fun!")
            assert(lst.isEmpty)
            bufferActor ! Append("awesome")
            succeed
          }
        }
      }
    }
    

    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 difference between stacking traits that extend BeforeAndAfterEach versus traits that implement withFixture is that setup and cleanup code happens before and after the test in BeforeAndAfterEach, but at the beginning and end of the test in withFixture. Thus if a withFixture method completes abruptly with an exception, it is considered a failed test. By contrast, if any of the beforeEach or afterEach methods of BeforeAndAfterEach complete abruptly, it is considered an aborted suite, which will result in a SuiteAborted event.

    Shared tests

    Sometimes you may want to run the same test code on different fixture objects. In other words, you may want to write tests that are "shared" by different fixture objects. To accomplish this in an AsyncFunSpec, you first place shared tests in behavior functions. These behavior functions will be invoked during the construction phase of any AsyncFunSpec that uses them, so that the tests they contain will be registered as tests in that AsyncFunSpec. For example, given this StackActor class:

    package org.scalatest.examples.asyncwordspec.sharedtests
    
    import scala.collection.mutable.ListBuffer
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext
    
    // Stack operations
    case class Push[T](value: T)
    sealed abstract class StackOp
    case object Pop extends StackOp
    case object Peek extends StackOp
    case object Size extends StackOp
    
    // Stack info
    case class StackInfo[T](top: Option[T], size: Int, max: Int) {
      require(size > 0, "size was less than zero")
      require(max > size, "max was less than size")
      val isFull: Boolean = size == max
      val isEmpty: Boolean = size == 0
    }
    
    class StackActor[T](Max: Int, name: String) {
    
      private final val buf = new ListBuffer[T]
    
      def !(push: Push[T]): Unit =
        synchronized {
          if (buf.size != Max)
            buf.prepend(push.value)
          else
            throw new IllegalStateException("can't push onto a full stack")
        }
    
      def ?(op: StackOp)(implicit c: ExecutionContext): Future[StackInfo[T]] =
        synchronized {
          op match {
            case Pop =>
              Future {
                if (buf.size != 0)
                  StackInfo(Some(buf.remove(0)), buf.size, Max)
                else
                  throw new IllegalStateException("can't pop an empty stack")
              }
            case Peek =>
              Future {
                if (buf.size != 0)
                  StackInfo(Some(buf(0)), buf.size, Max)
                else
                  throw new IllegalStateException("can't peek an empty stack")
              }
            case Size =>
              Future { StackInfo(None, buf.size, Max) }
          }
        }
    
      override def toString: String = name
    }
    

    You may want to test the stack represented by the StackActor class in different states: empty, full, with one item, with one item less than capacity, etc. You may find you have several tests that make sense any time the stack is non-empty. Thus you'd ideally want to run those same tests for three stack fixture objects: a full stack, a stack with a one item, and a stack with one item less than capacity. With shared tests, you can factor these tests out into a behavior function, into which you pass the stack fixture to use when running the tests. So in your AsyncFunSpec for StackActor, you'd invoke the behavior function three times, passing in each of the three stack fixtures so that the shared tests are run for all three fixtures.

    You can define a behavior function that encapsulates these shared tests inside the AsyncWordSpec that uses them. If they are shared between different AsyncFunSpecs, however, you could also define them in a separate trait that is mixed into each AsyncFunSpec that uses them. For example, here the nonEmptyStackActor behavior function (in this case, a behavior method) is defined in a trait along with another method containing shared tests for non-full stacks:

    import org.scalatest.AsyncWordSpec
    
    trait AsyncWordSpecStackBehaviors { this: AsyncWordSpec =>
    
      def nonEmptyStackActor(createNonEmptyStackActor: => StackActor[Int],
            lastItemAdded: Int, name: String): Unit = {
    
        ("return non-empty StackInfo when Size is fired at non-empty stack actor: " + name) in {
          val stackActor = createNonEmptyStackActor
          val futureStackInfo = stackActor ? Size
          futureStackInfo map { stackInfo =>
            assert(!stackInfo.isEmpty)
          }
        }
    
        ("return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: " + name) in {
          val stackActor = createNonEmptyStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePeek <- stackActor ? Size
              afterPeek <- stackActor ? Peek
            } yield (beforePeek, afterPeek)
          futurePair map { case (beforePeek, afterPeek) =>
            assert(afterPeek.top == Some(lastItemAdded))
            assert(afterPeek.size == beforePeek.size)
          }
        }
    
        ("return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: " + name) in {
          val stackActor = createNonEmptyStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePop <- stackActor ? Size
              afterPop <- stackActor ? Pop
            } yield (beforePop, afterPop)
          futurePair map { case (beforePop, afterPop) =>
            assert(afterPop.top == Some(lastItemAdded))
            assert(afterPop.size == beforePop.size - 1)
          }
        }
      }
    
      def nonFullStackActor(createNonFullStackActor: => StackActor[Int], name: String): Unit = {
    
        ("return non-full StackInfo when Size is fired at non-full stack actor: " + name) in {
          val stackActor = createNonFullStackActor
          val futureStackInfo = stackActor ? Size
          futureStackInfo map { stackInfo =>
            assert(!stackInfo.isFull)
          }
        }
    
        ("return before and after StackInfo that has existing size + 1 and new item as top when Push is fired at non-full stack actor: " + name) in {
          val stackActor = createNonFullStackActor
          val futurePair: Future[(StackInfo[Int], StackInfo[Int])] =
            for {
              beforePush <- stackActor ? Size
              afterPush <- { stackActor ! Push(7); stackActor ? Peek }
            } yield (beforePush, afterPush)
          futurePair map { case (beforePush, afterPush) =>
            assert(afterPush.top == Some(7))
            assert(afterPush.size == beforePush.size + 1)
          }
        }
      }
    }
    

    Given these behavior functions, you could invoke them directly, but AsyncWordSpec offers a DSL for the purpose, which looks like this:

    behave like nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName)
    behave like nonFullStackActor(almostEmptyStackActor, almostEmptyStackActorName)
    

    Here's an example:

    class StackSpec extends AsyncWordSpec with AsyncWordSpecStackBehaviors {
    
      val Max = 10
      val LastValuePushed = Max - 1
    
      // Stack fixture creation methods
      val emptyStackActorName = "empty stack actor"
      def emptyStackActor = new StackActor[Int](Max, emptyStackActorName )
    
      val fullStackActorName = "full stack actor"
      def fullStackActor = {
        val stackActor = new StackActor[Int](Max, fullStackActorName )
        for (i <- 0 until Max)
          stackActor ! Push(i)
        stackActor
      }
    
      val almostEmptyStackActorName = "almost empty stack actor"
      def almostEmptyStackActor = {
        val stackActor = new StackActor[Int](Max, almostEmptyStackActorName )
        stackActor ! Push(LastValuePushed)
        stackActor
      }
    
      val almostFullStackActorName = "almost full stack actor"
      def almostFullStackActor = {
        val stackActor = new StackActor[Int](Max, almostFullStackActorName)
        for (i <- 1 to LastValuePushed)
          stackActor ! Push(i)
        stackActor
      }
    
      "A Stack" when {
        "empty" should {
          "be empty" in {
            val stackActor = emptyStackActor
            val futureStackInfo = stackActor ? Size
            futureStackInfo map { stackInfo =>
              assert(stackInfo.isEmpty)
            }
          }
    
          "complain on peek" in {
            recoverToSucceededIf[IllegalStateException] {
              emptyStackActor ? Peek
            }
          }
    
          "complain on pop" in {
            recoverToSucceededIf[IllegalStateException] {
              emptyStackActor ? Pop
            }
          }
        }
        "non-empty" should {
          behave like nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName)
          behave like nonFullStackActor(almostEmptyStackActor, almostEmptyStackActorName)
          behave like nonEmptyStackActor(almostFullStackActor, LastValuePushed, almostFullStackActorName)
          behave like nonFullStackActor(almostFullStackActor, almostFullStackActorName)
        }
        "full" should {
          "be full" in {
            val stackActor = fullStackActor
            val futureStackInfo = stackActor ? Size
            futureStackInfo map { stackInfo =>
              assert(stackInfo.isFull)
            }
          }
          behave like nonEmptyStackActor(fullStackActor, LastValuePushed, fullStackActorName)
          "complain on a push" in {
            val stackActor = fullStackActor
            assertThrows[IllegalStateException] {
              stackActor ! Push(10)
            }
          }
        }
      }
    }
    

    If you load these classes into the Scala interpreter (with scalatest's JAR file on the class path), and execute it, you'll see:

    scala> org.scalatest.run(new StackSpec)
    StackSpec:
    A Stack
      when empty
      - should be empty
      - should complain on peek
      - should complain on pop
      when non-empty
      - should return non-empty StackInfo when Size is fired at non-empty stack actor: almost empty stack actor
      - should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost empty stack actor
      - should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost empty stack actor
      - should return non-full StackInfo when Size is fired at non-full stack actor: almost empty stack actor
      - should return before and after StackInfo that has existing size + 1 and new item as top when Push is fired at non-full stack actor: almost empty stack actor
      - should return non-empty StackInfo when Size is fired at non-empty stack actor: almost full stack actor
      - should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost full stack actor
      - should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost full stack actor
      - should return non-full StackInfo when Size is fired at non-full stack actor: almost full stack actor
      - should return before and after StackInfo that has existing size + 1 and new item as top when Push is fired at non-full stack actor: almost full stack actor
      when full
      - should be full
      - should return non-empty StackInfo when Size is fired at non-empty stack actor: full stack actor
      - should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: full stack actor
      - should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: full stack actor
      - should complain on a push
    
    

    One thing to keep in mind when using shared tests is that in ScalaTest, each test in a suite must have a unique name. If you register the same tests repeatedly in the same suite, one problem you may encounter is an exception at runtime complaining that multiple tests are being registered with the same test name. Although in an AsyncWordSpec, the when, should, can and must clause is a nesting construct analogous to AsyncFunSpec's describe clause, you many sometimes need to do a bit of extra work to ensure that the test names are unique. If a duplicate test name problem shows up in an AsyncFunSpec, you'll need to pass in a prefix or suffix string to add to each test name. You can call toString on the shared fixture object, or pass this string the same way you pass any other data needed by the shared tests. This is the approach taken by the previous AsyncFunSpecStackBehaviors example.

    Given this AsyncFunSpecStackBehaviors trait, calling it with the almostEmptyStackActor fixture, like this:

    behave like nonEmptyStackActor(almostEmptyStackActor, LastValuePushed, almostEmptyStackActorName)
    

    yields test names:

    • A Stack when non-empty should return non-empty StackInfo when Size is fired at non-empty stack actor: almost empty stack actor
    • A Stack when non-empty should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost empty stack actor
    • A Stack when non-empty should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost empty stack actor

    Whereas calling it with the almostFullStackActor fixture, like this:

    behave like nonEmptyStackActor(almostFullStackActor, LastValuePushed, almostFullStackActorName)
    

    yields different test names:

    • A Stack when non-empty should return non-empty StackInfo when Size is fired at non-empty stack actor: almost full stack actor
    • A Stack when non-empty should return before and after StackInfo that has existing size and lastItemAdded as top when Peek is fired at non-empty stack actor: almost full stack actor
    • A Stack when non-empty should return before and after StackInfo that has existing size - 1 and lastItemAdded as top when Pop is fired at non-empty stack actor: almost full stack actor
  21. trait AsyncWordSpecLike extends AsyncTestSuite with AsyncTestRegistration with ShouldVerb with MustVerb with CanVerb with Informing with Notifying with Alerting with Documenting

    Permalink

    Implementation trait for class AsyncWordSpec, which facilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.

    Implementation trait for class AsyncWordSpec, which facilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.

    AsyncWordSpec 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 AsyncWordSpec into some other class, you can use this trait instead, because class AsyncWordSpec does nothing more than extend this trait and add a nice toString implementation.

    See the documentation of the class for a detailed overview of AsyncWordSpec.

    Annotations
    @JSExportDescendentClasses( true ) @Finders()
  22. trait BeforeAndAfter extends SuiteMixin

    Permalink

    Trait that can be mixed into suites that need code executed before and after running each test.

    Trait that can be mixed into suites that need code executed before and after running each test.

    Recommended Usage: Use trait BeforeAndAfter when you need to perform the same side-effects before and/or after tests, rather than at the beginning or end of tests. Note: For more insight into where BeforeAndAfter 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. Trait BeforeAndAfter offers one way to eliminate such code duplication: a before clause that will register code to be run before each test, and an after clause that will register code to be run after.

    Here's an example:

    package org.scalatest.examples.flatspec.beforeandafter
    
    import org.scalatest._
    import collection.mutable.ListBuffer
    
    class ExampleSpec extends FlatSpec with BeforeAndAfter {
    
      val builder = new StringBuilder
      val buffer = new ListBuffer[String]
    
      before {
        builder.append("ScalaTest is ")
      }
    
      after {
        builder.clear()
        buffer.clear()
      }
    
      "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)
      }
    }
    

    The before and after methods can each only be called once per Suite, and cannot be invoked after run has been invoked. If either of the registered before or after functions complete abruptly with an exception, it will be reported as an aborted suite and no more tests will be attempted in that suite.

    Note that the only way before and after code can communicate with test code is via some side-effecting mechanism, commonly by reassigning instance vars or by changing the state of mutable objects held from instance vals (as in this example). If using instance vars or mutable objects held from instance vals you wouldn't be able to run tests in parallel in the same instance of the test class unless you synchronized access to the shared, mutable state. This is why ScalaTest's ParallelTestExecution trait extends OneInstancePerTest. By running each test in its own instance of the class, each test has its own copy of the instance variables, so you don't need to synchronize. Were you to mix ParallelTestExecution into the ExampleSuite above, the tests would run in parallel just fine without any synchronization needed on the mutable StringBuilder and ListBuffer[String] objects.

    Although BeforeAndAfter provides a minimal-boilerplate way to execute code before and after tests, it isn't designed to enable stackable traits, because the order of execution would be non-obvious. If you want to factor out before and after code that is common to multiple test suites, you should use trait BeforeAndAfterEach instead.

    The advantage this trait has over BeforeAndAfterEach is that its syntax is more concise. The main disadvantage is that it is not stackable, whereas BeforeAndAfterEach is. I.e., you can write several traits that extend BeforeAndAfterEach and provide beforeEach methods that include a call to super.beforeEach, and mix them together in various combinations. By contrast, only one call to the before registration function is allowed in a suite or spec that mixes in BeforeAndAfter. In addition, BeforeAndAfterEach allows you to access the config map and test name via the TestData passed to its beforeEach and afterEach methods, whereas BeforeAndAfter gives you no access to the config map.

  23. trait BeforeAndAfterAll extends SuiteMixin

    Permalink

    Stackable trait that can be mixed into suites that need methods invoked before and after executing the suite.

    Stackable trait that can be mixed into suites that need methods invoked before and after executing the suite.

    This trait allows code to be executed before and/or after all the tests and nested suites of a suite are run. This trait overrides run and calls the beforeAll method, then calls super.run. After the super.run invocation completes, whether it returns normally or completes abruptly with an exception, this trait's run method will invoke afterAll.

    Trait BeforeAndAfterAll defines beforeAll and afterAll methods that take no parameters. This trait's implementation of these methods do nothing.

    For example, the following ExampleSpec mixes in BeforeAndAfterAll and in beforeAll, creates and writes to a temp file. Each test class, ExampleSpec and all its nested suites--OneSpec, TwoSpec, RedSpec, and BlueSpec--tests that the file exists. After all of the nested suites have executed, afterAll is invoked, which deletes the file. (Note: if you're unfamiliar with the withFixture(OneArgTest) approach to shared fixtures, check out the documentation for trait fixture.FlatSpec.)

    package org.scalatest.examples.beforeandafterall
    
    import org.scalatest._
    import java.io._
    
    trait TempFileExistsSpec extends fixture.FlatSpecLike {
    
      protected val tempFileName = "tmp.txt"
    
      type FixtureParam = File
      override def withFixture(test: OneArgTest) = {
        val file = new File(tempFileName)
        withFixture(test.toNoArgTest(file)) // loan the fixture to the test
      }
    
      "The temp file" should ("exist in " + suiteName) in { file =>
        assert(file.exists)
      }
    }
    
    class OneSpec extends TempFileExistsSpec
    class TwoSpec extends TempFileExistsSpec
    class RedSpec extends TempFileExistsSpec
    class BlueSpec extends TempFileExistsSpec
    
    class ExampleSpec extends Suites(
      new OneSpec,
      new TwoSpec,
      new RedSpec,
      new BlueSpec
    ) with TempFileExistsSpec with BeforeAndAfterAll {
    
      // Set up the temp file needed by the test, taking
      // a file name from the config map
      override def beforeAll() {
        val writer = new FileWriter(tempFileName)
        try writer.write("Hello, suite of tests!")
        finally writer.close()
      }
    
      // Delete the temp file
      override def afterAll() {
        val file = new File(tempFileName)
        file.delete()
      }
    }
    

    If you do supply a mapping for "tempFileName" in the config map, you'll see that the temp file is available to all the tests:

    scala> org.scalatest.run(new ExampleSpec)
    ExampleSpec:
    OneSpec:
    The temp file
    - should exist in OneSpec
    TwoSpec:
    The temp file
    - should exist in TwoSpec
    RedSpec:
    The temp file
    - should exist in RedSpec
    BlueSpec:
    The temp file
    - should exist in BlueSpec
    The temp file
    - should exist in ExampleSpec
    

    Note: this trait uses the Status result of Suite's "run" methods to ensure that the code in afterAll is executed after all the tests and nested suites are executed even if a Distributor is passed.

    Note that it is not guaranteed that afterAll is invoked from the same thread as beforeAll, so if there's any shared state between beforeAll and afterAll you'll need to make sure they are synchronized correctly.

  24. trait BeforeAndAfterAllConfigMap extends SuiteMixin

    Permalink

    Trait that can be mixed into suites that need methods that make use of the config map invoked before and/or after executing the suite.

    Trait that can be mixed into suites that need methods that make use of the config map invoked before and/or after executing the suite.

    This trait allows code to be executed before and/or after all the tests and nested suites of a suite are run. This trait overrides run and calls the beforeAll(ConfigMap) method, then calls super.run. After the super.run invocation completes, whether it returns normally or completes abruptly with an exception, this trait's run method will invoke afterAll(ConfigMap).

    Note that this trait differs from BeforeAndAfterAll in that it gives the beforeAll and afterAll code access to the config map. If you don't need the config map, use BeforeAndAfterAll instead.

    Trait BeforeAndAfterAllConfigMap defines beforeAll and afterAll methods that take a configMap. This trait's implemention of each method does nothing.

    For example, the following ExampleSpec mixes in BeforeAndAfterAllConfigMap and in beforeAll, creates and writes to a temp file, taking the name of the temp file from the configMap. This same configMap is then passed to the run methods of the nested suites, OneSpec, TwoSpec, RedSpec, and BlueSpec, so those suites can access the filename and, therefore, the file's contents. After all of the nested suites have executed, afterAll is invoked, which again grabs the file name from the configMap and deletes the file. Each of these five test classes extend trait TempFileExistsSpec, which defines a test that ensures the temp file exists. (Note: if you're unfamiliar with the withFixture(OneArgTest) approach to shared fixtures, check out the documentation for trait fixture.FlatSpec.)

    package org.scalatest.examples.beforeandafterallconfigmap
    
    import org.scalatest._
    import java.io._
    
    trait TempFileExistsSpec extends fixture.FlatSpec {
    
      type FixtureParam = File
      override def withFixture(test: OneArgTest) = {
        val fileName = test.configMap.getRequired[String]("tempFileName")
        val file = new File(fileName)
        withFixture(test.toNoArgTest(file)) // loan the fixture to the test
      }
    
      "The temp file" should ("exist in " + suiteName) in { file =>
        assert(file.exists)
      }
    }
    
    class OneSpec extends TempFileExistsSpec
    class TwoSpec extends TempFileExistsSpec
    class RedSpec extends TempFileExistsSpec
    class BlueSpec extends TempFileExistsSpec
    
    class ExampleSpec extends Suites(
      new OneSpec,
      new TwoSpec,
      new RedSpec,
      new BlueSpec
    ) with TempFileExistsSpec with BeforeAndAfterAllConfigMap {
    
      private val tempFileName = "tempFileName"
    
      // Set up the temp file needed by the test, taking
      // a file name from the config map
      override def beforeAll(cm: ConfigMap) {
        assume(
          cm.isDefinedAt(tempFileName),
          "must place a temp file name in the config map under the key: " + tempFileName
        )
        val fileName = cm.getRequired[String](tempFileName)
        val writer = new FileWriter(fileName)
        try writer.write("Hello, suite of tests!")
        finally writer.close()
      }
    
      // Delete the temp file
      override def afterAll(cm: ConfigMap) {
        val fileName = cm.getRequired[String]("tempFileName")
        val file = new File(fileName)
        file.delete()
      }
    }
    

    Running the above class in the interpreter will give an error if you don't supply a mapping for "tempFileName" in the config map:

    scala> org.scalatest.run(new ExampleSpec)
    ExampleSpec:
    Exception encountered when invoking run on a suite. *** ABORTED ***
      Exception encountered when invoking run on a suite. (:30)
    *** RUN ABORTED ***
      An exception or error caused a run to abort: must place a temp file name in the config map under the key: tempFileName (:30)
    

    If you do supply a mapping for "tempFileName" in the config map, you'll see that the temp file is available to all the tests:

    scala> (new ExampleSpec).execute(configMap = ConfigMap("tempFileName" -> "tmp.txt"))
    ExampleSpec:
    OneSpec:
    The temp file
    - should exist in OneSpec
    TwoSpec:
    The temp file
    - should exist in TwoSpec
    RedSpec:
    The temp file
    - should exist in RedSpec
    BlueSpec:
    The temp file
    - should exist in BlueSpec
    The temp file
    - should exist in ExampleSpec
    

    Note: As of 2.0.M5, this trait uses the newly added Status result of Suite's "run" methods to ensure that the code in afterAll is executed after all the tests and nested suites are executed even if a Distributor is passed.

    Note that it is not guaranteed that afterAll is invoked from the same thread as beforeAll, so if there's any shared state between beforeAll and afterAll you'll need to make sure they are synchronized correctly.

  25. trait BeforeAndAfterEach extends SuiteMixin

    Permalink

    Stackable trait that can be mixed into suites that need code executed before and/or after running each test.

    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.

  26. trait BeforeAndAfterEachTestData extends SuiteMixin

    Permalink

    Stackable trait that can be mixed into suites that need code that makes use of test data (test name, tags, config map, etc.) executed before and/or after running each test.

    Stackable trait that can be mixed into suites that need code that makes use of test data (test name, tags, config map, etc.) executed before and/or after running each test.

    Recommended Usage: Use trait BeforeAndAfterEachTestData when you want to stack traits that perform side-effects before and/or after tests, rather than at the beginning or end of tests, when you need access to any test data (such as the config map) in the before and/or after code. Note: For more insight into where BeforeAndAfterEachTestData 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. Trait BeforeAndAfterEachTestData offers one way to eliminate such code duplication: a beforeEach(TestData) method that will be run before each test (like JUnit's setUp), and an afterEach(TestData) method that will be run after (like JUnit's tearDown).

    Here's an example:

    package org.scalatest.examples.flatspec.composingbeforeandaftereachtestdata
    
    import org.scalatest._
    import collection.mutable.ListBuffer
    
    trait Builder extends BeforeAndAfterEachTestData { this: Suite =>
    
      val builder = new StringBuilder
    
      override def beforeEach(td: TestData) {
        builder.append(td.name)
        super.beforeEach(td) // To be stackable, must call super.beforeEach(TestData)
      }
    
      override def afterEach(td: TestData) {
        try {
          super.afterEach(td) // To be stackable, must call super.afterEach(TestData)
        }
        finally {
          builder.clear()
        }
      }
    }
    
    trait Buffer extends BeforeAndAfterEachTestData { this: Suite =>
    
      val buffer = new ListBuffer[String]
    
      override def afterEach(td: TestData) {
        try {
          super.afterEach(td) // To be stackable, must call super.afterEach(TestData)
        }
        finally {
          buffer.clear()
        }
      }
    }
    
    class ExampleSpec extends FlatSpec with Builder with Buffer {
    
      "Testing" should "be easy" in {
        builder.append("!")
        assert(builder.toString === "Testing should be easy!")
        assert(buffer.isEmpty)
        buffer += "sweet"
      }
    
      it should "be fun" in {
        builder.append("!")
        assert(builder.toString === "Testing should be fun!")
        assert(buffer.isEmpty)
        buffer += "clear"
      }
    }
    

    To get the same ordering as withFixture, place your super.beforeEach(TestData) call at the end of each beforeEach(TestData) method, and the super.afterEach(TestData) call at the beginning of each afterEach(TestData) method, as shown in the previous example. It is a good idea to invoke super.afterEach(TestData) 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(TestData) throws an exception.

    Besides enabling trait stacking, the other main advantage of BeforeAndAfterEachTestData over BeforeAndAfter is that BeforeAndAfterEachTestData allows you to make use of test data (such as the test name and config map) in your before and/or after code, whereas BeforeAndAfter does not.

    The main disadvantage of BeforeAndAfterEachTestData compared to BeforeAndAfter and BeforeAndAfterEach is that BeforeAndAfterEachTestData requires more boilerplate. If you don't need trait stacking or access to the test data, use BeforeAndAfter instead of BeforeAndAfterEachTestData. If you need trait stacking, but not access to the TestData, use BeforeAndAfterEach instead.

  27. trait CancelAfterFailure extends TestSuiteMixin

    Permalink

    Trait that when mixed into a TestSuite cancels any remaining tests in that TestSuite instance after a test fails.

    Trait that when mixed into a TestSuite cancels any remaining tests in that TestSuite instance after a test fails.

    The intended use case for this trait is if you have a suite of long-running tests that are related such that if one fails, you aren't interested in running the others, you can use this trait to simply cancel any remaining tests, so you need not wait long for them to complete.

    Note that this trait only cancels tests in the same TestSuite instance, because it uses a private volatile instance variable as a flag to indicate whether or not a test has failed. If you are running each test in its own instance, therefore, it would not cancel the remaining tests, because they would not see the same flag. For this reason, this trait contains a final implementation of a method defined in OneInstancePerTest, to prevent it from being mixed into any class that also mixes in OneInstancePerTest, including by mixing in ParallelTestExecution or a path trait.

  28. case class Canceled(exception: TestCanceledException) extends Exceptional with Product with Serializable

    Permalink

    Outcome for a test that was canceled, containing an exception describing the cause of the cancelation.

  29. trait Checkpoints extends AnyRef

    Permalink

    Trait providing class Checkpoint, which enables multiple assertions to be performed within a test, with any failures accumulated and reported together at the end of the test.

    Trait providing class Checkpoint, which enables multiple assertions to be performed within a test, with any failures accumulated and reported together at the end of the test.

    Because ScalaTest uses exceptions to signal failed assertions, normally execution of a test will stop as soon as the first failed assertion is encountered. Trait Checkpoints provides an option when you want to continue executing the remainder of the test body, or part of it, even if an assertion has already failed in that test.

    To use a Checkpoint (once you've mixed in or imported the members of trait Checkpoints), you first need to create one, like this:

    val cp = new Checkpoint
    

    Then give the Checkpoint assertions to execute by passing them (via a by-name parameter) to its apply method, like this:

    val (x, y) = (1, 2)
    cp { x should be < 0 }
    cp { y should be > 9 }
    

    Both of the above assertions will fail, but it won't be reported yet. The Checkpoint will execute them right away, each time its apply method is invoked. But it will catch the TestFailedExceptions and save them, only reporting them later when reportAll is invoked. Thus, at the end of the test, you must call reportAll, like this:

    cp.reportAll()
    

    This reportAll invocation will complete abruptly with a TestFailedException whose message includes the message, source file, and line number of each of the checkpointed assertions that previously failed. For example:

    1 was not less than 0 (in Checkpoint) at ExampleSpec.scala:12
    2 was not greater than 9 (in Checkpoint) at ExampleSpec.scala:13
    

    Make sure you invoke reportAll before the test completes, otherwise any failures that were detected by the Checkpoint will not be reported.

    Note that a Checkpoint will catch and record for later reporting (via reportAll) exceptions that mix in StackDepth except for TestCanceledException, TestRegistrationClosedException, NotAllowedException, and DuplicateTestNameException. If a block of code passed to a Checkpoint's apply method completes abruptly with any of the StackDepth exceptions in the previous list, or any non-StackDepth exception, that invocation of the apply method will complete abruptly with the same exception immediately. Unless you put reportAll in a finally clause and handle this case, such an unexpected exception will cause you to lose any information about assertions that failed earlier in the test and were recorded by the Checkpoint.

  30. trait CompleteLastly extends AnyRef

    Permalink

    Trait that provides a complete-lastly construct, which ensures cleanup code in lastly is executed whether the code passed to complete completes abruptly with an exception or successfully results in a Future, FutureOutcome, or other type with an implicit Futuristic instance.

    Trait that provides a complete-lastly construct, which ensures cleanup code in lastly is executed whether the code passed to complete completes abruptly with an exception or successfully results in a Future, FutureOutcome, or other type with an implicit Futuristic instance.

    This trait is mixed into ScalaTest's async testing styles, to make it easy to ensure cleanup code will execute whether code that produces a "futuristic" value (any type F for which a Futuristic[F] instance is implicitly available). ScalaTest provides implicit Futuristic instances for Future[T] for any type T and FutureOutcome.

    If the future-producing code passed to complete throws an exception, the cleanup code passed to lastly will be executed immediately, and the same exception will be rethrown, unless the code passed to lastly also completes abruptly with an exception. In that case, complete-lastly will complete abruptly with the exception thrown by the code passed to lastly (this mimics the behavior of finally).

    Otherwise, if the code passed to complete successfully returns a Future (or other "futuristic" type), complete-lastly will register the cleanup code to be performed once the future completes and return a new future that will complete once the original future completes and the subsequent cleanup code has completed execution. The future returned by complete-lastly will have the same result as the original future passed to complete, unless the cleanup code throws an exception. If the cleanup code passed to lastly throws an exception, the future returned by lastly will fail with that exception.

    The complete-lastly syntax is intended to be used to ensure cleanup code is executed in async testing styles like try-finally is used in traditional testing styles. Here's an example of complete-lastly used in withFixture in an async testing style:

    // Your implementation
    override def withFixture(test: NoArgAsyncTest) = {
    
      // Perform setup here
    
      complete {
        super.withFixture(test) // Invoke the test function
      } lastly {
        // Perform cleanup here
      }
    }
    

  31. final class CompositeStatus extends Status with Serializable

    Permalink

    Composite Status that aggregates its completion and failed states of set of other Statuses passed to its constructor.

    Composite Status that aggregates its completion and failed states of set of other Statuses passed to its constructor.

  32. class ConfigMap extends Map[String, Any] with MapLike[String, Any, ConfigMap] with Serializable

    Permalink

    A map of configuration data.

    A map of configuration data.

    A ConfigMap can be populated from the Runner command line via -D arguments. Runner passes it to many methods where you can use it to configure your test runs. For example, Runner passed the ConfigMap to:

    • the apply method of Reporters via RunStarting events
    • the run method of Suite
    • the runNestedSuites method of Suite
    • the runTests method of Suite
    • the runTest method of Suite
    • the withFixture(NoArgTest) method of Suite
    • the withFixture(OneArgTest) method of fixture.Suite
    • the beforeEach(TestData) method of BeforeAndAfterEachTestData
    • the afterEach(TestData) method of BeforeAndAfterEachTestData

    In addition to accessing the ConfigMap in overriden implementations of the above methods, you can also transform and pass along a modified ConfigMap.

    A ConfigMap maps string keys to values of any type, i.e., it is a Map[String, Any]. To get a configuration value in a variable of the actual type of that value, therefore, you'll need to perform an unsafe cast. If this cast fails, you'll get an exception, which so long as the ConfigMap is used only in tests, will result in either a failed or canceled test or aborted suite. To give such exceptions nice stack depths and error messages, and to eliminate the need for using asInstanceOf in your test code, ConfigMap provides three methods for accessing values at expected types.

    The getRequired method returns the value bound to a key cast to a specified type, or throws TestCanceledException if either the key is not bound or is bound to an incompatible type. Here's an example:

    val tempFileName: String = configMap.getRequired[String]("tempFileName")
    

    The getOptional method returns the value bound to a key cast to a specified type, wrapped in a Some, returns None if the key is not bound, or throws TestCanceledException if the key exists but is bound to an incompatible type. Here's an example:

    val tempFileName: Option[String] = configMap.getOptional[String]("tempFileName")
    

    The getWithDefault method returns the value bound to a key cast to a specified type, returns a specified default value if the key is not bound, or throws TestCanceledException if the key exists but is either not bound or is bound to an incompatible type. Here's an example:

    val tempFileName: String = configMap.getWithDefault[String]("tempFileName", "tmp.txt")
    

  33. trait DiagrammedAssertions extends Assertions

    Permalink

    Sub-trait of Assertions that override assert and assume methods to include a diagram showing the values of expression in the error message when the assertion or assumption fails.

    Sub-trait of Assertions that override assert and assume methods to include a diagram showing the values of expression in the error message when the assertion or assumption fails.

    Here are some examples:

    scala> import DiagrammedAssertions._
    import DiagrammedAssertions._
    
    scala> assert(a == b || c >= d)
    org.scalatest.exceptions.TestFailedException:
    
    assert(a == b || c >= d)
           | |  | |  | |  |
           1 |  2 |  3 |  4
             |    |    false
             |    false
             false
    
            at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:422)
            ...
    
    scala> assert(xs.exists(_ == 4))
    org.scalatest.exceptions.TestFailedException:
    
    assert(xs.exists(_ == 4))
           |  |
           |  false
           List(1, 2, 3)
    
            at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:422)
            ...
    
    scala> assert("hello".startsWith("h") && "goodbye".endsWith("y"))
    org.scalatest.exceptions.TestFailedException:
    
    assert("hello".startsWith("h") && "goodbye".endsWith("y"))
           |       |          |    |  |         |        |
           "hello" true       "h"  |  "goodbye" false    "y"
                                   false
    
            at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:422)
            ...
    
    scala> assert(num.isInstanceOf[Int])
    org.scalatest.exceptions.TestFailedException:
    
    assert(num.isInstanceOf[Int])
           |   |
           1.0 false
    
            at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:422)
            ...
    
    scala> assert(Some(2).isEmpty)
    org.scalatest.exceptions.TestFailedException:
    
    assert(Some(2).isEmpty)
           |    |  |
           |    2  false
           Some(2)
    
            at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:422)
            ...
    
    scala> assert(None.isDefined)
    org.scalatest.exceptions.TestFailedException:
    
    assert(None.isDefined)
           |    |
           None false
    
            at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:422)
            ...
    
    scala> assert(xs.exists(i => i > 10))
    org.scalatest.exceptions.TestFailedException:
    
    assert(xs.exists(i => i > 10))
           |  |
           |  false
           List(1, 2, 3)
    
            at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:422)
            ...
    
    

    If the expression passed to assert or assume spans more than one line, DiagrammedAssertions falls back to the default style of error message, since drawing a diagram would be difficult. Here's an example showing how DiagrammedAssertions will treat a multi-line assertion (i.e., you don't get a diagram):

    scala> assert("hello".startsWith("h") &&
         |   "goodbye".endsWith("y"))
    org.scalatest.exceptions.TestFailedException: "hello" started with "h", but "goodbye" did not end with "y"
            at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:422)
            ...
    

    Also, since an expression diagram essentially represents multi-line ascii art, if a clue string is provided, it appears above the diagram, not after it. It will often also show up in the diagram:

    scala> assert(None.isDefined, "Don't do this at home")
    org.scalatest.exceptions.TestFailedException: Don't do this at home
    
    assert(None.isDefined, "Don't do this at home")
           |    |
           None false
    
            at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:422)
            ...
    
    scala> assert(None.isDefined,
         |   "Don't do this at home")
    org.scalatest.exceptions.TestFailedException: Don't do this at home
    
    assert(None.isDefined,
           |    |
           None false
    
            at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:422)
            ...
    

    Trait DiagrammedAssertions was inspired by Peter Niederwieser's work in Spock and Expecty.

  34. trait DiagrammedExpr[T] extends AnyRef

    Permalink

    A trait that represent an expression recorded by DiagrammedExprMacro, which includes the following members:

    A trait that represent an expression recorded by DiagrammedExprMacro, which includes the following members:

    • a boolean value
    • an anchor that records the position of this expression
    • anchor values of this expression (including sub-expressions)

    DiagrammedExpr is used by code generated from DiagrammedAssertionsMacro, it needs to be public so that the generated code can be compiled. It is expected that ScalaTest users would ever need to use DiagrammedExpr directly.

  35. trait DistributedSuiteSorter extends AnyRef

    Permalink

    A sorter for the events of a run's distributed suites.

    A sorter for the events of a run's distributed suites.

    This trait is used, for example, when -PS is passed to Runner, to sort the events of distributed suites such that each suite's events are propagated together, with a timeout if an event takes too long.

  36. trait DistributedTestSorter extends AnyRef

    Permalink

    A sorter for the events of a suite's distributed tests.

    A sorter for the events of a suite's distributed tests.

    This trait is used, for example, by ParallelTestExecution to sort the events of tests back into sequential order, with a timeout if an event takes too long.

  37. trait Distributor extends AnyRef

    Permalink

    Trait whose instances facilitate parallel execution of Suites.

    Trait whose instances facilitate parallel execution of Suites. An optional Distributor is passed to the run method of Suite. If a Distributor is indeed passed, trait Suite's implementation of run will populate that Distributor with its nested Suites (by passing them to the Distributor's apply method) rather than executing the nested Suites directly. It is then up to another thread or process to execute those Suites.

    If you have a set of nested Suites that must be executed sequentially, you can mix in trait SequentialNestedSuiteExecution, which overrides runNestedSuites and calls super's runNestedSuites implementation, passing in None for the Distributor.

    Implementations of this trait must be thread safe.

  38. class DoNotDiscover extends Annotation with Annotation with ClassfileAnnotation

    Permalink
  39. trait Documenter extends AnyRef

    Permalink

    Trait to which markup text tests can be reported.

    Trait to which markup text tests can be reported.

    Note: Documenter will be described in more detail in a future 2.0 milestone release. As of this release you can't see its effects yet.

  40. trait Documenting extends AnyRef

    Permalink

    Trait that contains a markup method, which can be used to send markup to the Reporter.

    Trait that contains a markup method, which can be used to send markup to the Reporter.

  41. final case class DynaTags(suiteTags: Map[String, Set[String]], testTags: Map[String, Map[String, Set[String]]]) extends Serializable with Product

    Permalink

    Dynamic tags for a run.

    Dynamic tags for a run.

    Instances of this class are passed to the Filter constructor to support running selected suites and tests via dynamic tagging. For example, dynamic tags can be used to rerun tests that failed previously, or tests selected via a wildcard from Runner or the Scala interpreter.

    suiteTags

    a map from String suite ID to a set of tags for that suite.

    testTags

    a map from String suite ID to a map, whose keys are test names and values the tags for that test.

    Exceptions thrown

    NullPointerException if either suiteTags or testTags is null

  42. trait EitherValues extends AnyRef

    Permalink

    Trait that provides an implicit conversion that adds left.value and right.value methods to Either, which will return the selected value of the Either if defined, or throw TestFailedException if not.

    Trait that provides an implicit conversion that adds left.value and right.value methods to Either, which will return the selected value of the Either if defined, or throw TestFailedException if not.

    This construct allows you to express in one statement that an Either should be left or right and that its value should meet some expectation. Here's are some examples:

    either1.right.value should be > 9
    either2.left.value should be ("Muchas problemas")
    

    Or, using assertions instead of matcher expressions:

    assert(either1.right.value > 9)
    assert(either2.left.value === "Muchas problemas")
    

    Were you to simply invoke right.get or left.get on the Either, if the Either wasn't defined as expected (e.g., it was a Left when you expected a Right), it would throw a NoSuchElementException:

    val either: Either[String, Int] = Left("Muchas problemas")
    
    either.right.get should be > 9 // either.right.get throws NoSuchElementException
    

    The NoSuchElementException would cause the test to fail, but without providing a stack depth pointing to the failing line of test code. This stack depth, provided by TestFailedException (and a few other ScalaTest exceptions), makes it quicker for users to navigate to the cause of the failure. Without EitherValues, to get a stack depth exception you would need to make two statements, like this:

    val either: Either[String, Int] = Left("Muchas problemas")
    
    either should be ('right) // throws TestFailedException
    either.right.get should be > 9
    

    The EitherValues trait allows you to state that more concisely:

    val either: Either[String, Int] = Left("Muchas problemas")
    
    either.right.value should be > 9 // either.right.value throws TestFailedException
    

  43. case class Entry[K, V](key: K, value: V) extends Product with Serializable

    Permalink

    A case class implementation of java.util.Map.Entry to make it easier to test Java Maps with ScalaTest Matchers.

    A case class implementation of java.util.Map.Entry to make it easier to test Java Maps with ScalaTest Matchers.

    In Java, java.util.Map is not a subtype of java.util.Collection, and does not actually define an element type. You can ask a Java Map for an “entry set” via the entrySet method, which will return the Map's key/value pairs wrapped in a set of java.util.Map.Entry, but a Map is not actually a collection of Entry. To make Java Maps easier to work with, however, ScalaTest matchers allows you to treat a Java Map as a collection of Entry, and defines this convenience implementation of java.util.Map.Entry. Here's how you use it:

    javaMap should contain (Entry(2, 3))
    javaMap should contain oneOf (Entry(2, 3), Entry(3, 4))
    

    key

    the key of this entry

    value

    the value of this entry

  44. sealed abstract class Exceptional extends Outcome

    Permalink

    Superclass for the two outcomes of running a test that contain an exception: Failed and Canceled.

    Superclass for the two outcomes of running a test that contain an exception: Failed and Canceled.

    This class provides a toOption method that returns a Some wrapping the contained exception, and an isExceptional field with the value true. It's companion object provides an extractor that enables patterns that match a test that either failed or canceled, as in:

    outcome match {
      case Exceptional(ex) => // handle failed or canceled case
      case _ => // handle succeeded, pending, or omitted case
    }
    

  45. case class Failed(exception: Throwable) extends Exceptional with Product with Serializable

    Permalink

    Outcome for a test that failed, containing an exception describing the cause of the failure.

    Outcome for a test that failed, containing an exception describing the cause of the failure.

    Note: the difference between this Failed class and the similarly named FailedStatus object is that an instance of this class indicates one test failed, whereas the FailedStatus object indicates either one or more tests failed and/or one or more suites aborted during a run. Both are used as the result type of Suite lifecycle methods, but Failed is a possible result of withFixture, whereas FailedStatus is a possible result of run, runNestedSuites, runTests, or runTest. In short, Failed is always just about one test, whereas FailedStatus could be about something larger: multiple tests or an entire suite.

  46. class FeatureSpec extends FeatureSpecLike

    Permalink

    A suite of tests in which each test represents one scenario of a feature.

    A suite of tests in which each test represents one scenario of a feature. FeatureSpec is intended for writing tests that are "higher level" than unit tests, for example, integration tests, functional tests, and acceptance tests. You can use FeatureSpec for unit testing if you prefer, however.

    Recommended Usage: Class FeatureSpec is primarily intended for acceptance testing, including facilitating the process of programmers working alongside non-programmers to define the acceptance requirements.

    Although not required, FeatureSpec is often used together with GivenWhenThen to express acceptance requirements in more detail. Here's an example:

    package org.scalatest.examples.featurespec
    
    import org.scalatest._
    
    class TVSet {
      private var on: Boolean = false
      def isOn: Boolean = on
      def pressPowerButton() {
        on = !on
      }
    }
    
    class TVSetSpec extends FeatureSpec with GivenWhenThen {
    
      info("As a TV set owner")
      info("I want to be able to turn the TV on and off")
      info("So I can watch TV when I want")
      info("And save energy when I'm not watching TV")
    
      feature("TV power button") {
        scenario("User presses power button when TV is off") {
    
          Given("a TV set that is switched off")
          val tv = new TVSet
          assert(!tv.isOn)
    
          When("the power button is pressed")
          tv.pressPowerButton()
    
          Then("the TV should switch on")
          assert(tv.isOn)
        }
    
        scenario("User presses power button when TV is on") {
    
          Given("a TV set that is switched on")
          val tv = new TVSet
          tv.pressPowerButton()
          assert(tv.isOn)
    
          When("the power button is pressed")
          tv.pressPowerButton()
    
          Then("the TV should switch off")
          assert(!tv.isOn)
        }
      }
    }
    

    Note: for more information on the calls to Given, When, and Then, see the documentation for trait GivenWhenThen and the Informers section below.

    A FeatureSpec contains feature clauses and scenarios. You define a feature clause with feature, and a scenario with scenario. Both feature and scenario are methods, defined in FeatureSpec, which will be invoked by the primary constructor of TVSetSpec. A feature clause describes a feature of the subject (class or other entity) you are specifying and testing. In the previous example, the subject under specification and test is a TV set. The feature being specified and tested is the behavior of a TV set when its power button is pressed. With each scenario you provide a string (the spec text) that specifies the behavior of the subject for one scenario in which the feature may be used, and a block of code that tests that behavior. You place the spec text between the parentheses, followed by the test code between curly braces. The test code will be wrapped up as a function passed as a by-name parameter to scenario, which will register the test for later execution.

    A FeatureSpec's lifecycle has two phases: the registration phase and the ready phase. It starts in registration phase and enters ready phase the first time run is called on it. It then remains in ready phase for the remainder of its lifetime.

    Scenarios can only be registered with the scenario method while the FeatureSpec is in its registration phase. Any attempt to register a scenario after the FeatureSpec has entered its ready phase, i.e., after run has been invoked on the FeatureSpec, will be met with a thrown TestRegistrationClosedException. The recommended style of using FeatureSpec is to register tests during object construction as is done in all the examples shown here. If you keep to the recommended style, you should never see a TestRegistrationClosedException.

    Each scenario represents one test. The name of the test is the spec text passed to the scenario method. The feature name does not appear as part of the test name. In a FeatureSpec, therefore, you must take care to ensure that each test has a unique name (in other words, that each scenario has unique spec text).

    When you run a FeatureSpec, it will send Formatters in the events it sends to the Reporter. ScalaTest's built-in reporters will report these events in such a way that the output is easy to read as an informal specification of the subject being tested. For example, were you to run TVSetSpec from within the Scala interpreter:

    scala> org.scalatest.run(new TVSetSpec)
    

    You would see:

    TVSetSpec:
    As a TV set owner
    I want to be able to turn the TV on and off
    So I can watch TV when I want
    And save energy when I'm not watching TV
    Feature: TV power button
      Scenario: User presses power button when TV is off
        Given a TV set that is switched off
        When the power button is pressed
        Then the TV should switch on
      Scenario: User presses power button when TV is on
        Given a TV set that is switched on
        When the power button is pressed
        Then the TV should switch off
    

    Or, to run just the “Feature: TV power button Scenario: User presses power button when TV is on” method, you could pass that test's name, or any unique substring of the name, such as "TV is on". Here's an example:

    scala> org.scalatest.run(new TVSetSpec, "TV is on")
    TVSetSpec:
    As a TV set owner
    I want to be able to turn the TV on and off
    So I can watch TV when I want
    And save energy when I'm not watching TV
    Feature: TV power button
      Scenario: User presses power button when TV is on
        Given a TV set that is switched on
        When the power button is pressed
        Then the TV should switch off
    

    Note: Trait FeatureSpec's syntax is in part inspired by Cucumber, a Ruby BDD framework.

    Ignored tests

    To support the common use case of temporarily disabling a test, with the good intention of resurrecting the test at a later time, FeatureSpec provides registration methods that start with ignore instead of scenario. For example, to temporarily disable the test named addition, just change “scenario” into “ignore,” like this:

    package org.scalatest.examples.featurespec.ignore
    
    import org.scalatest.FeatureSpec
    
    class TVSet {
      private var on: Boolean = false
      def isOn: Boolean = on
      def pressPowerButton() {
        on = !on
      }
    }
    
    class TVSetSpec extends FeatureSpec {
    
      feature("TV power button") {
        ignore("User presses power button when TV is off") {
          val tv = new TVSet
          assert(!tv.isOn)
          tv.pressPowerButton()
          assert(tv.isOn)
        }
    
        scenario("User presses power button when TV is on") {
          val tv = new TVSet
          tv.pressPowerButton()
          assert(tv.isOn)
          tv.pressPowerButton()
          assert(!tv.isOn)
        }
      }
    }
    

    If you run this version of SetSpec with:

    scala> org.scalatest.run(new TVSetSpec)
    

    It will run only the second scenario and report that the first scenario was ignored:

    TVSetSpec:
    Feature: TV power button
      Scenario: User presses power button when TV is off !!! IGNORED !!!
      Scenario: User presses power button when TV is on
    

    Informers

    One of the parameters to FeatureSpec's run method is a Reporter, which will collect and report information about the running suite of tests. Information about suites and tests that were run, whether tests succeeded or failed, and tests that were ignored will be passed to the Reporter as the suite runs. Most often the default reporting done by FeatureSpec's methods will be sufficient, but occasionally you may wish to provide custom information to the Reporter from a test. For this purpose, an Informer that will forward information to the current Reporter is provided via the info parameterless method. You can pass the extra information to the Informer via its apply method. The Informer will then pass the information to the Reporter via an InfoProvided event.

    One use case for the Informer is to pass more information about a scenario to the reporter. For example, the GivenWhenThen trait provides methods that use the implicit info provided by FeatureSpec to pass such information to the reporter. You can see this in action in the initial example of this trait's documentation.

    Documenters

    FeatureSpec also provides a markup method that returns a Documenter, which allows you to send to the Reporter text formatted in Markdown syntax. You can pass the extra information to the Documenter via its apply method. The Documenter will then pass the information to the Reporter via an MarkupProvided event.

    Here's an example FlatSpec that uses markup:

    package org.scalatest.examples.featurespec.markup
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends FeatureSpec with GivenWhenThen {
    
      markup { """
    
    Mutable Set
    -----------
    
    A set is a collection that contains no duplicate elements.
    
    To implement a concrete mutable set, you need to provide implementations
    of the following methods:
    
        def contains(elem: A): Boolean
        def iterator: Iterator[A]
        def += (elem: A): this.type
        def -= (elem: A): this.type
    
    If you wish that methods like `take`,
    `drop`, `filter` return the same kind of set,
    you should also override:
    
         def empty: This
    
    It is also good idea to override methods `foreach` and
    `size` for efficiency.
    
      """ }
    
      feature("An element can be added to an empty mutable Set") {
        scenario("When an element is added to an empty mutable Set") {
          Given("an empty mutable Set")
          val set = mutable.Set.empty[String]
    
          When("an element is added")
          set += "clarity"
    
          Then("the Set should have size 1")
          assert(set.size === 1)
    
          And("the Set should contain the added element")
          assert(set.contains("clarity"))
    
          markup("This test finished with a **bold** statement!")
        }
      }
    }
    

    Although all of ScalaTest's built-in reporters will display the markup text in some form, the HTML reporter will format the markup information into HTML. Thus, the main purpose of markup is to add nicely formatted text to HTML reports. Here's what the above SetSpec would look like in the HTML reporter:

    Notifiers and alerters

    ScalaTest records text passed to info and markup during tests, and sends the recorded text in the recordedEvents field of test completion events like TestSucceeded and TestFailed. This allows string reporters (like the standard out reporter) to show info and markup text after the test name in a color determined by the outcome of the test. For example, if the test fails, string reporters will show the info and markup text in red. If a test succeeds, string reporters will show the info and markup text in green. While this approach helps the readability of reports, it means that you can't use info to get status updates from long running tests.

    To get immediate (i.e., non-recorded) notifications from tests, you can use note (a Notifier) and alert (an Alerter). Here's an example showing the differences:

    package org.scalatest.examples.featurespec.note
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends FeatureSpec {
    
      feature("An element can be added to an empty mutable Set") {
        scenario("When an element is added to an empty mutable Set") {
    
          info("info is recorded")
          markup("markup is *also* recorded")
          note("notes are sent immediately")
          alert("alerts are also sent immediately")
    
          val set = mutable.Set.empty[String]
          set += "clarity"
          assert(set.size === 1)
          assert(set.contains("clarity"))
        }
      }
    }
    

    Because note and alert information is sent immediately, it will appear before the test name in string reporters, and its color will be unrelated to the ultimate outcome of the test: note text will always appear in green, alert text will always appear in yellow. Here's an example:

    scala> org.scalatest.run(new SetSpec)
    SetSpec:
    Feature: An element can be added to an empty mutable Set
      + notes are sent immediately
      + alerts are also sent immediately
      Scenario: When an element is added to an empty mutable Set
        info is recorded
      + markup is *also* recorded
    

    Another example is slowpoke notifications. If you find a test is taking a long time to complete, but you're not sure which test, you can enable slowpoke notifications. ScalaTest will use an Alerter to fire an event whenever a test has been running longer than a specified amount of time.

    In summary, use info and markup for text that should form part of the specification output. Use note and alert to send status notifications. (Because the HTML reporter is intended to produce a readable, printable specification, info and markup text will appear in the HTML report, but note and alert text will not.)

    Pending tests

    A pending test is one that has been given a name but is not yet implemented. The purpose of pending tests is to facilitate a style of testing in which documentation of behavior is sketched out before tests are written to verify that behavior (and often, before the behavior of the system being tested is itself implemented). Such sketches form a kind of specification of what tests and functionality to implement later.

    To support this style of testing, a test can be given a name that specifies one bit of behavior required by the system being tested. The test can also include some code that sends more information about the behavior to the reporter when the tests run. At the end of the test, it can call method pending, which will cause it to complete abruptly with TestPendingException.

    Because tests in ScalaTest can be designated as pending with TestPendingException, both the test name and any information sent to the reporter when running the test can appear in the report of a test run. (In other words, the code of a pending test is executed just like any other test.) However, because the test completes abruptly with TestPendingException, the test will be reported as pending, to indicate the actual test, and possibly the functionality, has not yet been implemented. You can mark tests as pending in a FeatureSpec like this:

    package org.scalatest.examples.featurespec.pending
    
    import org.scalatest.FeatureSpec
    
    class TVSet {
      private var on: Boolean = false
      def isOn: Boolean = on
      def pressPowerButton() {
        on = !on
      }
    }
    
    class TVSetSpec extends FeatureSpec {
    
      feature("TV power button") {
    
        scenario("User presses power button when TV is off") (pending)
    
        scenario("User presses power button when TV is on") {
          val tv = new TVSet
          tv.pressPowerButton()
          assert(tv.isOn)
          tv.pressPowerButton()
          assert(!tv.isOn)
        }
      }
    }
    

    (Note: "(pending)" is the body of the test. Thus the test contains just one statement, an invocation of the pending method, which throws TestPendingException.) If you run this version of TVSetSpec with:

    scala> org.scalatest.run(new TVSetSpec)
    

    It will run both tests, but report that When empty should have size 0 is pending. You'll see:

    TVSetSpec:
    Feature: TV power button
      Scenario: User presses power button when TV is off (pending)
      Scenario: User presses power button when TV is on
    

    One difference between an ignored test and a pending one is that an ignored test is intended to be used during a significant refactorings of the code under test, when tests break and you don't want to spend the time to fix all of them immediately. You can mark some of those broken tests as ignored temporarily, so that you can focus the red bar on just failing tests you actually want to fix immediately. Later you can go back and fix the ignored tests. In other words, by ignoring some failing tests temporarily, you can more easily notice failed tests that you actually want to fix. By contrast, a pending test is intended to be used before a test and/or the code under test is written. Pending indicates you've decided to write a test for a bit of behavior, but either you haven't written the test yet, or have only written part of it, or perhaps you've written the test but don't want to implement the behavior it tests until after you've implemented a different bit of behavior you realized you need first. Thus ignored tests are designed to facilitate refactoring of existing code whereas pending tests are designed to facilitate the creation of new code.

    One other difference between ignored and pending tests is that ignored tests are implemented as a test tag that is excluded by default. Thus an ignored test is never executed. By contrast, a pending test is implemented as a test that throws TestPendingException (which is what calling the pending method does). Thus the body of pending tests are executed up until they throw TestPendingException. The reason for this difference is that it enables your unfinished test to send InfoProvided messages to the reporter before it completes abruptly with TestPendingException, as shown in the previous example on Informers that used the GivenWhenThen trait. For example, the following snippet in a FeatureSpec:

    package org.scalatest.examples.featurespec.infopending
    
    import org.scalatest._
    
    class TVSet {
      private var on: Boolean = false
    
      def isOn: Boolean = on
    
      def pressPowerButton() {
        on = !on
      }
    }
    
    class TVSetSpec extends FeatureSpec with GivenWhenThen {
    
      info("As a TV set owner")
      info("I want to be able to turn the TV on and off")
      info("So I can watch TV when I want")
      info("And save energy when I'm not watching TV")
    
      feature("TV power button") {
        scenario("User presses power button when TV is off") {
          Given("a TV that is switched off")
          When("the power button is pressed")
          Then("the TV should switch on")
          pending
        }
    
        scenario("User presses power button when TV is on") {
          Given("a TV that is switched on")
          When("the power button is pressed")
          Then("the TV should switch off")
          pending
        }
      }
    }
    

    Would yield the following output when run in the interpreter:

    scala> org.scalatest.run(new TVSetSpec)
    TVSetSpec:
    As a TV set owner
    I want to be able to turn the TV on and off
    So I can watch TV when I want
    And save energy when I'm not watching TV
    Feature: TV power button
      Scenario: User presses power button when TV is off (pending)
        Given a TV that is switched off
        When the power button is pressed
        Then the TV should switch on
      Scenario: User presses power button when TV is on (pending)
        Given a TV that is switched on
        When the power button is pressed
        Then the TV should switch off 
    

    Tagging tests

    A FeatureSpec's tests may be classified into groups by tagging them with string names. As with any suite, when executing a FeatureSpec, groups of tests can optionally be included and/or excluded. To tag a FeatureSpec's tests, you pass objects that extend class org.scalatest.Tag to methods that register tests. Class Tag takes one parameter, a string name. If you have created tag annotation interfaces as described in the Tag documentation, then you will probably want to use tag names on your test functions that match. To do so, simply pass the fully qualified names of the tag interfaces to the Tag constructor. For example, if you've defined a tag annotation interface with fully qualified name, com.mycompany.tags.DbTest, then you could create a matching tag for FeatureSpecs like this:

    package org.scalatest.examples.featurespec.tagging
    
    import org.scalatest.Tag
    
    object DbTest extends Tag("com.mycompany.tags.DbTest")
    

    Given these definitions, you could place FeatureSpec tests into groups with tags like this:

    import org.scalatest.FeatureSpec
    import org.scalatest.tagobjects.Slow
    
    class TVSet {
      private var on: Boolean = false
      def isOn: Boolean = on
      def pressPowerButton() {
        on = !on
      }
    }
    
    class TVSetSpec extends FeatureSpec {
    
      feature("TV power button") {
        scenario("User presses power button when TV is off", Slow) {
          val tv = new TVSet
          assert(!tv.isOn)
          tv.pressPowerButton()
          assert(tv.isOn)
        }
    
        scenario("User presses power button when TV is on", Slow, DbTest) {
          val tv = new TVSet
          tv.pressPowerButton()
          assert(tv.isOn)
          tv.pressPowerButton()
          assert(!tv.isOn)
        }
      }
    }
    

    This code marks both tests with the org.scalatest.tags.Slow tag, and the second test with the com.mycompany.tags.DbTest tag.

    The run method takes a Filter, whose constructor takes an optional Set[String] called tagsToInclude and a Set[String] called tagsToExclude. If tagsToInclude is None, all tests will be run except those those belonging to tags listed in the tagsToExclude Set. If tagsToInclude is defined, only tests belonging to tags mentioned in the tagsToInclude set, and not mentioned in tagsToExclude, will be run.

    It is recommended, though not required, that you create a corresponding tag annotation when you create a Tag object. A tag annotation (on the JVM, not Scala.js) allows you to tag all the tests of a FeatureSpec in one stroke by annotating the class. For more information and examples, see the documentation for class Tag. On Scala.js, to tag all tests of a suite, you'll need to tag each test individually at the test site.

    Shared fixtures

    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.

    ScalaTest recommends three techniques to eliminate such code duplication:

    • Refactor using Scala
    • Override withFixture
    • Mix in a before-and-after trait

    Each technique is geared towards helping you reduce code duplication without introducing instance vars, shared mutable objects, or other dependencies between tests. Eliminating shared mutable state across tests will make your test code easier to reason about and more amenable for parallel test execution.

    The following sections describe these techniques, including explaining the recommended usage for each. But first, here's a table summarizing the options:

    Refactor using Scala when different tests need different fixtures.
    get-fixture methods The extract method refactor helps you create a fresh instances of mutable fixture objects in each test that needs them, but doesn't help you clean them up when you're done.
    fixture-context objects By placing fixture methods and fields into traits, you can easily give each test just the newly created fixtures it needs by mixing together traits. Use this technique when you need different combinations of mutable fixture objects in different tests, and don't need to clean up after.
    loan-fixture methods Factor out dupicate code with the loan pattern when different tests need different fixtures that must be cleaned up afterwards.
    Override withFixture when most or all tests need the same fixture.
    withFixture(NoArgTest) The recommended default approach when most or all tests need the same fixture treatment. This general technique allows you, for example, to perform side effects at the beginning and end of all or most tests, transform the outcome of tests, retry tests, make decisions based on test names, tags, or other test data. Use this technique unless:
    Different tests need different fixtures (refactor using Scala instead)
    An exception in fixture code should abort the suite, not fail the test (use a before-and-after trait instead)
    You have objects to pass into tests (override withFixture(OneArgTest) instead)
    withFixture(OneArgTest) Use when you want to pass the same fixture object or objects as a parameter into all or most tests.
    Mix in a before-and-after trait when you want an aborted suite, not a failed test, if the fixture code fails.
    BeforeAndAfter Use this boilerplate-buster when you need to perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.
    BeforeAndAfterEach Use when you want to stack traits that perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.

    Calling get-fixture methods

    If you need to create the same mutable fixture objects in multiple tests, and don't need to clean them up after using them, the simplest approach is to write one or more get-fixture methods. A get-fixture method returns a new instance of a needed fixture object (or a holder object containing multiple fixture objects) each time it is called. You can call a get-fixture method at the beginning of each test that needs the fixture, storing the returned object or objects in local variables. Here's an example:

    package org.scalatest.examples.featurespec.getfixture
    
    import org.scalatest.FeatureSpec
    import collection.mutable.ListBuffer
    
    class ExampleSpec extends FeatureSpec {
    
      class Fixture {
        val builder = new StringBuilder("ScalaTest is designed to ")
        val buffer = new ListBuffer[String]
      }
    
      def fixture = new Fixture
    
      feature("Simplicity") {
        scenario("User needs to read test code written by others") {
          val f = fixture
          f.builder.append("encourage clear code!")
          assert(f.builder.toString === "ScalaTest is designed to encourage clear code!")
          assert(f.buffer.isEmpty)
          f.buffer += "sweet"
        }
    
        scenario("User needs to understand what the tests are doing") {
          val f = fixture
          f.builder.append("be easy to reason about!")
          assert(f.builder.toString === "ScalaTest is designed to be easy to reason about!")
          assert(f.buffer.isEmpty)
        }
      }
    }
    

    The “f.” in front of each use of a fixture object provides a visual indication of which objects are part of the fixture, but if you prefer, you can import the the members with “import f._” and use the names directly.

    If you need to configure fixture objects differently in different tests, you can pass configuration into the get-fixture method. For example, you could pass in an initial value for a mutable fixture object as a parameter to the get-fixture method.

    Instantiating fixture-context objects

    An alternate technique that is especially useful when different tests need different combinations of fixture objects is to define the fixture objects as instance variables of fixture-context objects whose instantiation forms the body of tests. Like get-fixture methods, fixture-context objects are only appropriate if you don't need to clean up the fixtures after using them.

    To use this technique, you define instance variables intialized with fixture objects in traits and/or classes, then in each test instantiate an object that contains just the fixture objects needed by the test. Traits allow you to mix together just the fixture objects needed by each test, whereas classes allow you to pass data in via a constructor to configure the fixture objects. Here's an example in which fixture objects are partitioned into two traits and each test just mixes together the traits it needs:

    package org.scalatest.examples.featurespec.fixturecontext
    
    import collection.mutable.ListBuffer
    import org.scalatest.FeatureSpec
    
    class ExampleSpec extends FeatureSpec {
    
      trait Builder {
        val builder = new StringBuilder("ScalaTest is designed to ")
      }
    
      trait Buffer {
        val buffer = ListBuffer("ScalaTest", "is", "designed", "to")
      }
    
      feature("Simplicity") {
        // This test needs the StringBuilder fixture
        scenario("User needs to read test code written by others") {
          new Builder {
            builder.append("encourage clear code!")
            assert(builder.toString === "ScalaTest is designed to encourage clear code!")
          }
        }
    
        // This test needs the ListBuffer[String] fixture
        scenario("User needs to understand what the tests are doing") {
          new Buffer {
            buffer += ("be", "easy", "to", "reason", "about!")
            assert(buffer === List("ScalaTest", "is", "designed", "to", "be", "easy", "to", "reason", "about!"))
          }
        }
    
        // This test needs both the StringBuilder and ListBuffer
        scenario("User needs to write tests") {
          new Builder with Buffer {
            builder.append("be easy to learn!")
            buffer += ("be", "easy", "to", "remember", "how", "to", "write!")
            assert(builder.toString === "ScalaTest is designed to be easy to learn!")
            assert(buffer === List("ScalaTest", "is", "designed", "to", "be", "easy",
              "to", "remember", "how", "to", "write!"))
          }
        }
      }
    }
    

    Overriding withFixture(NoArgTest)

    Although the get-fixture method and fixture-context object approaches take care of setting up a fixture at the beginning of each test, they don't address the problem of cleaning up a fixture at the end of the test. If you just need to perform a side-effect at the beginning or end of a test, and don't need to actually pass any fixture objects into the test, you can override withFixture(NoArgTest), one of ScalaTest's lifecycle methods defined in trait Suite.

    Trait Suite's implementation of runTest passes a no-arg test function to withFixture(NoArgTest). It is withFixture's responsibility to invoke that test function. Suite's implementation of withFixture simply invokes the function, like this:

    // Default implementation in trait Suite
    protected def withFixture(test: NoArgTest) = {
      test()
    }
    

    You can, therefore, override withFixture to perform setup before and/or cleanup after invoking the test function. If you have cleanup to perform, you should invoke the test function inside a try block and perform the cleanup in a finally clause, in case an exception propagates back through withFixture. (If a test fails because of an exception, the test function invoked by withFixture will result in a Failed wrapping the exception. Nevertheless, best practice is to perform cleanup in a finally clause just in case an exception occurs.)

    The withFixture method is designed to be stacked, and to enable this, you should always call the super implementation of withFixture, and let it invoke the test function rather than invoking the test function directly. That is to say, instead of writing “test()”, you should write “super.withFixture(test)”, like this:

    // Your implementation
    override def withFixture(test: NoArgTest) = {
      // Perform setup
      try super.withFixture(test) // Invoke the test function
      finally {
        // Perform cleanup
      }
    }
    

    Here's an example in which withFixture(NoArgTest) is used to take a snapshot of the working directory if a test fails, and send that information to the reporter:

    package org.scalatest.examples.featurespec.noargtest
    
    import java.io.File
    import org.scalatest._
    
    class ExampleSpec extends FeatureSpec {
    
      override def withFixture(test: NoArgTest) = {
    
        super.withFixture(test) match {
          case failed: Failed =>
            val currDir = new File(".")
            val fileNames = currDir.list()
            info("Dir snapshot: " + fileNames.mkString(", "))
            failed
          case other => other
        }
      }
    
      scenario("This scenario should succeed") {
        assert(1 + 1 === 2)
      }
    
      scenario("This scenario should fail") {
        assert(1 + 1 === 3)
      }
    }
    

    Running this version of ExampleSuite in the interpreter in a directory with two files, hello.txt and world.txt would give the following output:

    scala> org.scalatest.run(new ExampleSpec)
    ExampleSpec:
    Scenario: This scenario should succeed
    Scenario: This scenario should fail *** FAILED ***
      2 did not equal 3 (:115)
      + Dir snapshot: hello.txt, world.txt 
    

    Note that the NoArgTest passed to withFixture, in addition to an apply method that executes the test, also includes the test name and the config map passed to runTest. Thus you can also use the test name and configuration objects in your withFixture implementation.

    Calling loan-fixture methods

    If you need to both pass a fixture object into a test and perform cleanup at the end of the test, you'll need to use the loan pattern. If different tests need different fixtures that require cleanup, you can implement the loan pattern directly by writing loan-fixture methods. A loan-fixture method takes a function whose body forms part or all of a test's code. It creates a fixture, passes it to the test code by invoking the function, then cleans up the fixture after the function returns.

    The following example shows three tests that use two fixtures, a database and a file. Both require cleanup after, so each is provided via a loan-fixture method. (In this example, the database is simulated with a StringBuffer.)

    package org.scalatest.examples.featurespec.loanfixture
    
    import java.util.concurrent.ConcurrentHashMap
    
    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)
      }
    }
    
    import org.scalatest.FeatureSpec
    import DbServer._
    import java.util.UUID.randomUUID
    import java.io._
    
    class ExampleSpec extends FeatureSpec {
    
      def withDatabase(testCode: Db => Any) {
        val dbName = randomUUID.toString
        val db = createDb(dbName) // create the fixture
        try {
          db.append("ScalaTest is designed to ") // perform setup
          testCode(db) // "loan" the fixture to the test
        }
        finally removeDb(dbName) // clean up the fixture
      }
    
      def withFile(testCode: (File, FileWriter) => Any) {
        val file = File.createTempFile("hello", "world") // create the fixture
        val writer = new FileWriter(file)
        try {
          writer.write("ScalaTest is designed to ") // set up the fixture
          testCode(file, writer) // "loan" the fixture to the test
        }
        finally writer.close() // clean up the fixture
      }
    
      feature("Simplicity") {
        // This test needs the file fixture
        scenario("User needs to read test code written by others") {
          withFile { (file, writer) =>
            writer.write("encourage clear code!")
            writer.flush()
            assert(file.length === 46)
          }
        }
        // This test needs the database fixture
        scenario("User needs to understand what the tests are doing") {
          withDatabase { db =>
            db.append("be easy to reason about!")
            assert(db.toString === "ScalaTest is designed to be easy to reason about!")
          }
        }
        // This test needs both the file and the database
        scenario("User needs to write tests") {
          withDatabase { db =>
            withFile { (file, writer) => // loan-fixture methods compose
              db.append("be easy to learn!")
              writer.write("be easy to remember how to write!")
              writer.flush()
              assert(db.toString === "ScalaTest is designed to be easy to learn!")
              assert(file.length === 58)
            }
          }
        }
      }
    }
    

    As demonstrated by the last test, loan-fixture methods compose. Not only do loan-fixture methods allow you to give each test the fixture it needs, they allow you to give a test multiple fixtures and clean everything up afterwards.

    Also demonstrated in this example is 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 this example. This keeps tests completely isolated, allowing you to run them in parallel if desired.

    ==== Overriding withFixture(OneArgTest) ==== If all or most tests need the same fixture, you can avoid some of the boilerplate of the loan-fixture method approach by using a fixture.FeatureSpec and overriding withFixture(OneArgTest). Each test in a fixture.FeatureSpec takes a fixture as a parameter, allowing you to pass the fixture into the test. You must indicate the type of the fixture parameter by specifying FixtureParam, and implement a withFixture method that takes a OneArgTest. This withFixture method is responsible for invoking the one-arg test function, so you can perform fixture set up before, and clean up after, invoking and passing the fixture into the test function. 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)
        }
      }
    }
    
    In this example, the tests actually required two fixture objects, a File and a FileWriter. In such situations you can simply define the FixtureParam type to be a tuple containing the objects, or as is done in this example, a case class containing the objects. For more information on the withFixture(OneArgTest) technique, see the documentation for fixture.FeatureSpec. ==== Mixing in BeforeAndAfter ==== In all the shared fixture examples shown so far, the activities of creating, setting up, and cleaning up the fixture objects have been performed during the test. This means that if an exception occurs during any of these activities, it will be reported as a test failure. Sometimes, however, you may want setup to happen before the test starts, and cleanup after the test has completed, so that if an exception occurs during setup or cleanup, the entire suite aborts and no more tests are attempted. The simplest way to accomplish this in ScalaTest is to mix in trait BeforeAndAfter. With this trait you can denote a bit of code to run before each test with before and/or after each test each test with after, like this:
    package org.scalatest.examples.featurespec.beforeandafter
    
    import org.scalatest._
    import collection.mutable.ListBuffer
    
    class ExampleSpec extends FeatureSpec with BeforeAndAfter {
    
      val builder = new StringBuilder
      val buffer = new ListBuffer[String]
    
      before {
        builder.append("ScalaTest is designed to ")
      }
    
      after {
        builder.clear()
        buffer.clear()
      }
    
      feature("Simplicity") {
        scenario("User needs to read test code written by others") {
          builder.append("encourage clear code!")
          assert(builder.toString === "ScalaTest is designed to encourage clear code!")
          assert(buffer.isEmpty)
          buffer += "sweet"
        }
    
        scenario("User needs to understand what the tests are doing") {
          builder.append("be easy to reason about!")
          assert(builder.toString === "ScalaTest is designed to be easy to reason about!")
          assert(buffer.isEmpty)
        }
      }
    }
    
    Note that the only way before and after code can communicate with test code is via some side-effecting mechanism, commonly by reassigning instance vars or by changing the state of mutable objects held from instance vals (as in this example). If using instance vars or mutable objects held from instance vals you wouldn't be able to run tests in parallel in the same instance of the test class (on the JVM, not Scala.js) unless you synchronized access to the shared, mutable state. This is why ScalaTest's ParallelTestExecution trait extends OneInstancePerTest. By running each test in its own instance of the class, each test has its own copy of the instance variables, so you don't need to synchronize. If you mixed ParallelTestExecution into the ExampleSuite above, the tests would run in parallel just fine without any synchronization needed on the mutable StringBuilder and ListBuffer[String] objects. Although BeforeAndAfter provides a minimal-boilerplate way to execute code before and after tests, it isn't designed to enable stackable traits, because the order of execution would be non-obvious. If you want to factor out before and after code that is common to multiple test suites, you should use trait BeforeAndAfterEach instead, as shown later in the next section, composing fixtures by stacking traits. == Composing fixtures by stacking traits == In larger projects, teams often end up with several different fixtures that test classes need in different combinations, and possibly initialized (and cleaned up) in different orders. A good way to accomplish this in ScalaTest is to factor the individual fixtures into traits that can be composed using the stackable trait pattern. This can be done, for example, by placing withFixture methods in several traits, each of which call super.withFixture. Here's an example in which the StringBuilder and ListBuffer[String] fixtures used in the previous examples have been factored out into two stackable fixture traits named Builder and Buffer:
    package org.scalatest.examples.featurespec.composingwithfixture
    
    import org.scalatest._
    import collection.mutable.ListBuffer
    
    trait Builder extends TestSuiteMixin { this: TestSuite =>
    
      val builder = new StringBuilder
    
      abstract override def withFixture(test: NoArgTest) = {
        builder.append("ScalaTest is designed to ")
        try super.withFixture(test) // To be stackable, must call super.withFixture
        finally builder.clear()
      }
    }
    
    trait Buffer extends TestSuiteMixin { this: TestSuite =>
    
      val buffer = new ListBuffer[String]
    
      abstract override def withFixture(test: NoArgTest) = {
        try super.withFixture(test) // To be stackable, must call super.withFixture
        finally buffer.clear()
      }
    }
    
    class ExampleSpec extends FeatureSpec with Builder with Buffer {
    
      feature("Simplicity") {
        scenario("User needs to read test code written by others") {
          builder.append("encourage clear code!")
          assert(builder.toString === "ScalaTest is designed to encourage clear code!")
          assert(buffer.isEmpty)
          buffer += "clear"
        }
    
        scenario("User needs to understand what the tests are doing") {
          builder.append("be easy to reason about!")
          assert(builder.toString === "ScalaTest is designed to be easy to reason about!")
          assert(buffer.isEmpty)
          buffer += "easy"
        }
      }
    }
    
    By mixing in both the Builder and Buffer traits, ExampleSuite gets both fixtures, which will be initialized before each test and cleaned up after. The order the traits are mixed together determines the order of execution. In this case, Builder is “super” to Buffer. If you wanted Buffer to be “super” to Builder, you need only switch the order you mix them together, like this:
    class Example2Spec extends FeatureSpec with Buffer with Builder
    
    And if you only need one fixture you mix in only that trait:
    class Example3Spec extends FeatureSpec with Builder
    
    Another way to create stackable fixture traits is by extending the BeforeAndAfterEach and/or BeforeAndAfterAll traits. BeforeAndAfterEach has 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). Similarly, BeforeAndAfterAll has a beforeAll method that will be run before all tests, and an afterAll method that will be run after all tests. Here's what the previously shown example would look like if it were rewritten to use the BeforeAndAfterEach methods instead of withFixture:
    package org.scalatest.examples.featurespec.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 designed to ")
        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 FeatureSpec with Builder with Buffer {
    
      feature("Simplicity") {
        scenario("User needs to read test code written by others") {
          builder.append("encourage clear code!")
          assert(builder.toString === "ScalaTest is designed to encourage clear code!")
          assert(buffer.isEmpty)
          buffer += "clear"
        }
    
        scenario("User needs to understand what the tests are doing") {
          builder.append("be easy to reason about!")
          assert(builder.toString === "ScalaTest is designed to be easy to reason about!")
          assert(buffer.isEmpty)
          buffer += "easy"
        }
      }
    }
    
    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 difference between stacking traits that extend BeforeAndAfterEach versus traits that implement withFixture is that setup and cleanup code happens before and after the test in BeforeAndAfterEach, but at the beginning and end of the test in withFixture. Thus if a withFixture method completes abruptly with an exception, it is considered a failed test. By contrast, if any of the beforeEach or afterEach methods of BeforeAndAfterEach complete abruptly, it is considered an aborted suite, which will result in a SuiteAborted event. == Shared scenarios == Sometimes you may want to run the same test code on different fixture objects. In other words, you may want to write tests that are "shared" by different fixture objects. To accomplish this in a FeatureSpec, you first place shared tests (i.e., shared scenarios) in behavior functions. These behavior functions will be invoked during the construction phase of any FeatureSpec that uses them, so that the scenarios they contain will be registered as scenarios in that FeatureSpec. For example, given this stack class:
    import scala.collection.mutable.ListBuffer
    
    class Stack[T] {
    
      val MAX = 10
      private val buf = new ListBuffer[T]
    
      def push(o: T) {
        if (!full)
          buf.prepend(o)
        else
          throw new IllegalStateException("can't push onto a full stack")
      }
    
      def pop(): T = {
        if (!empty)
          buf.remove(0)
        else
          throw new IllegalStateException("can't pop an empty stack")
      }
    
      def peek: T = {
        if (!empty)
          buf(0)
        else
          throw new IllegalStateException("can't pop an empty stack")
      }
    
      def full: Boolean = buf.size == MAX
      def empty: Boolean = buf.size == 0
      def size = buf.size
    
      override def toString = buf.mkString("Stack(", ", ", ")")
    }
    
    You may want to test the Stack class in different states: empty, full, with one item, with one item less than capacity, etc. You may find you have several scenarios that make sense any time the stack is non-empty. Thus you'd ideally want to run those same scenarios for three stack fixture objects: a full stack, a stack with a one item, and a stack with one item less than capacity. With shared tests, you can factor these scenarios out into a behavior function, into which you pass the stack fixture to use when running the tests. So in your FeatureSpec for stack, you'd invoke the behavior function three times, passing in each of the three stack fixtures so that the shared scenarios are run for all three fixtures. You can define a behavior function that encapsulates these shared scenarios inside the FeatureSpec that uses them. If they are shared between different FeatureSpecs, however, you could also define them in a separate trait that is mixed into each FeatureSpec that uses them. For example, here the nonEmptyStack behavior function (in this case, a behavior method) is defined in a trait along with another method containing shared scenarios for non-full stacks:
    import org.scalatest.FeatureSpec
    import org.scalatest.GivenWhenThen
    import org.scalatestexamples.helpers.Stack
    
    trait FeatureSpecStackBehaviors { this: FeatureSpec with GivenWhenThen =>
    
      def nonEmptyStack(createNonEmptyStack: => Stack[Int], lastItemAdded: Int) {
    
        scenario("empty is invoked on this non-empty stack: " + createNonEmptyStack.toString) {
    
          Given("a non-empty stack")
          val stack = createNonEmptyStack
    
          When("empty is invoked on the stack")
          Then("empty returns false")
          assert(!stack.empty)
        }
    
        scenario("peek is invoked on this non-empty stack: " + createNonEmptyStack.toString) {
    
          Given("a non-empty stack")
          val stack = createNonEmptyStack
          val size = stack.size
    
          When("peek is invoked on the stack")
          Then("peek returns the last item added")
          assert(stack.peek === lastItemAdded)
    
          And("the size of the stack is the same as before")
          assert(stack.size === size)
        }
    
        scenario("pop is invoked on this non-empty stack: " + createNonEmptyStack.toString) {
    
          Given("a non-empty stack")
          val stack = createNonEmptyStack
          val size = stack.size
    
          When("pop is invoked on the stack")
          Then("pop returns the last item added")
          assert(stack.pop === lastItemAdded)
    
          And("the size of the stack one less than before")
          assert(stack.size === size - 1)
        }
      }
    
      def nonFullStack(createNonFullStack: => Stack[Int]) {
    
        scenario("full is invoked on this non-full stack: " + createNonFullStack.toString) {
    
          Given("a non-full stack")
          val stack = createNonFullStack
    
          When("full is invoked on the stack")
          Then("full returns false")
          assert(!stack.full)
        }
    
        scenario("push is invoked on this non-full stack: " + createNonFullStack.toString) {
    
          Given("a non-full stack")
          val stack = createNonFullStack
          val size = stack.size
    
          When("push is invoked on the stack")
          stack.push(7)
    
          Then("the size of the stack is one greater than before")
          assert(stack.size === size + 1)
    
          And("the top of the stack contains the pushed value")
          assert(stack.peek === 7)
        }
      }
    }
    
    Given these behavior functions, you could invoke them directly, but FeatureSpec offers a DSL for the purpose, which looks like this:
    scenariosFor(nonEmptyStack(stackWithOneItem, lastValuePushed))
    scenariosFor(nonFullStack(stackWithOneItem))
    
    If you prefer to use an imperative style to change fixtures, for example by mixing in BeforeAndAfterEach and reassigning a stack var in beforeEach, you could write your behavior functions in the context of that var, which means you wouldn't need to pass in the stack fixture because it would be in scope already inside the behavior function. In that case, your code would look like this:
    scenariosFor(nonEmptyStack) // assuming lastValuePushed is also in scope inside nonEmptyStack
    scenariosFor(nonFullStack)
    
    The recommended style, however, is the functional, pass-all-the-needed-values-in style. Here's an example:
    import org.scalatest.FeatureSpec
    import org.scalatest.GivenWhenThen
    import org.scalatestexamples.helpers.Stack
    
    class StackFeatureSpec extends FeatureSpec with GivenWhenThen with FeatureSpecStackBehaviors {
    
      // Stack fixture creation methods
      def emptyStack = new Stack[Int]
    
      def fullStack = {
        val stack = new Stack[Int]
        for (i <- 0 until stack.MAX)
          stack.push(i)
        stack
      }
    
      def stackWithOneItem = {
        val stack = new Stack[Int]
        stack.push(9)
        stack
      }
    
      def stackWithOneItemLessThanCapacity = {
        val stack = new Stack[Int]
        for (i <- 1 to 9)
          stack.push(i)
        stack
      }
    
      val lastValuePushed = 9
    
      feature("A Stack is pushed and popped") {
    
        scenario("empty is invoked on an empty stack") {
    
          Given("an empty stack")
          val stack = emptyStack
    
          When("empty is invoked on the stack")
          Then("empty returns true")
          assert(stack.empty)
        }
    
        scenario("peek is invoked on an empty stack") {
    
          Given("an empty stack")
          val stack = emptyStack
    
          When("peek is invoked on the stack")
          Then("peek throws IllegalStateException")
          assertThrows[IllegalStateException] {
            stack.peek
          }
        }
    
        scenario("pop is invoked on an empty stack") {
    
          Given("an empty stack")
          val stack = emptyStack
    
          When("pop is invoked on the stack")
          Then("pop throws IllegalStateException")
          assertThrows[IllegalStateException] {
            emptyStack.pop
          }
        }
    
        scenariosFor(nonEmptyStack(stackWithOneItem, lastValuePushed))
        scenariosFor(nonFullStack(stackWithOneItem))
    
        scenariosFor(nonEmptyStack(stackWithOneItemLessThanCapacity, lastValuePushed))
        scenariosFor(nonFullStack(stackWithOneItemLessThanCapacity))
    
        scenario("full is invoked on a full stack") {
    
          Given("an full stack")
          val stack = fullStack
    
          When("full is invoked on the stack")
          Then("full returns true")
          assert(stack.full)
        }
    
        scenariosFor(nonEmptyStack(fullStack, lastValuePushed))
    
        scenario("push is invoked on a full stack") {
    
          Given("an full stack")
          val stack = fullStack
    
          When("push is invoked on the stack")
          Then("push throws IllegalStateException")
          assertThrows[IllegalStateException] {
            stack.push(10)
          }
        }
      }
    }
    
    If you load these classes into the Scala interpreter (with scalatest's JAR file on the class path), and execute it, you'll see:
    scala> (new StackFeatureSpec).execute()
    Feature: A Stack is pushed and popped
      Scenario: empty is invoked on an empty stack
        Given an empty stack
        When empty is invoked on the stack
        Then empty returns true
      Scenario: peek is invoked on an empty stack
        Given an empty stack
        When peek is invoked on the stack
        Then peek throws IllegalStateException
      Scenario: pop is invoked on an empty stack
        Given an empty stack
        When pop is invoked on the stack
        Then pop throws IllegalStateException
      Scenario: empty is invoked on this non-empty stack: Stack(9)
        Given a non-empty stack
        When empty is invoked on the stack
        Then empty returns false
      Scenario: peek is invoked on this non-empty stack: Stack(9)
        Given a non-empty stack
        When peek is invoked on the stack
        Then peek returns the last item added
        And the size of the stack is the same as before
      Scenario: pop is invoked on this non-empty stack: Stack(9)
        Given a non-empty stack
        When pop is invoked on the stack
        Then pop returns the last item added
        And the size of the stack one less than before
      Scenario: full is invoked on this non-full stack: Stack(9)
        Given a non-full stack
        When full is invoked on the stack
        Then full returns false
      Scenario: push is invoked on this non-full stack: Stack(9)
        Given a non-full stack
        When push is invoked on the stack
        Then the size of the stack is one greater than before
        And the top of the stack contains the pushed value
      Scenario: empty is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1)
        Given a non-empty stack
        When empty is invoked on the stack
        Then empty returns false
      Scenario: peek is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1)
        Given a non-empty stack
        When peek is invoked on the stack
        Then peek returns the last item added
        And the size of the stack is the same as before
      Scenario: pop is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1)
        Given a non-empty stack
        When pop is invoked on the stack
        Then pop returns the last item added
        And the size of the stack one less than before
      Scenario: full is invoked on this non-full stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1)
        Given a non-full stack
        When full is invoked on the stack
        Then full returns false
      Scenario: push is invoked on this non-full stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1)
        Given a non-full stack
        When push is invoked on the stack
        Then the size of the stack is one greater than before
        And the top of the stack contains the pushed value
      Scenario: full is invoked on a full stack
        Given an full stack
        When full is invoked on the stack
        Then full returns true
      Scenario: empty is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
        Given a non-empty stack
        When empty is invoked on the stack
        Then empty returns false
      Scenario: peek is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
        Given a non-empty stack
        When peek is invoked on the stack
        Then peek returns the last item added
        And the size of the stack is the same as before
      Scenario: pop is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
        Given a non-empty stack
        When pop is invoked on the stack
        Then pop returns the last item added
        And the size of the stack one less than before
      Scenario: push is invoked on a full stack
        Given an full stack
        When push is invoked on the stack
        Then push throws IllegalStateException
    
    One thing to keep in mind when using shared tests is that in ScalaTest, each test in a suite must have a unique name. If you register the same tests repeatedly in the same suite, one problem you may encounter is an exception at runtime complaining that multiple tests are being registered with the same test name. Although in a FeatureSpec, the feature clause is a nesting construct analogous to FunSpec's describe clause, you many sometimes need to do a bit of extra work to ensure that the test names are unique. If a duplicate test name problem shows up in a FeatureSpec, you can pass in a prefix or suffix string to add to each test name. You can pass this string the same way you pass any other data needed by the shared tests, or just call toString on the shared fixture object. This is the approach taken by the previous FeatureSpecStackBehaviors example. Given this FeatureSpecStackBehaviors trait, calling it with the stackWithOneItem fixture, like this:
    scenariosFor(nonEmptyStack(stackWithOneItem, lastValuePushed))
    
    yields test names: - empty is invoked on this non-empty stack: Stack(9) - peek is invoked on this non-empty stack: Stack(9) - pop is invoked on this non-empty stack: Stack(9) Whereas calling it with the stackWithOneItemLessThanCapacity fixture, like this:
    scenariosFor(nonEmptyStack(stackWithOneItemLessThanCapacity, lastValuePushed))
    
    yields different test names: - empty is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1) - peek is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1) - pop is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1)

    Annotations
    @Finders()
  47. trait FeatureSpecLike extends TestSuite with TestRegistration with Informing with Notifying with Alerting with Documenting

    Permalink

    Implementation trait for class FeatureSpec, which represents a suite of tests in which each test represents one scenario of a feature.

    Implementation trait for class FeatureSpec, which represents a suite of tests in which each test represents one scenario of a feature.

    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 FeatureSpec into some other class, you can use this trait instead, because class 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 FeatureSpec.

    Annotations
    @Finders() @JSExportDescendentClasses( true )
  48. final class Filter extends Serializable

    Permalink

    Filter whose apply method determines which of the passed tests to run and ignore based on tags to include and exclude passed as as class parameters.

    Filter whose apply method determines which of the passed tests to run and ignore based on tags to include and exclude passed as as class parameters.

    This class handles the org.scalatest.Ignore tag specially, in that its apply method indicates which tests should be ignored based on whether they are tagged with org.scalatest.Ignore. If "org.scalatest.Ignore" is not passed in the tagsToExclude set, it will be implicitly added. However, if the tagsToInclude option is defined, and the contained set does not include "org.scalatest.Ignore", then only those tests that are both tagged with org.scalatest.Ignore and at least one of the tags in the tagsToInclude set will be included in the result of apply and marked as ignored (so long as the test is not also marked with a tag other than org.scalatest.Ignore that is a member of the tagsToExclude set. For example, if SlowAsMolasses is a member of the tagsToInclude set and a test is tagged with both org.scalatest.Ignore and SlowAsMolasses, and SlowAsMolasses appears in the tagsToExclude set, the SlowAsMolasses tag will "overpower" the org.scalatest.Ignore tag, and the test will be filtered out entirely rather than being ignored.

    Exceptions thrown

    IllegalArgumentException if tagsToInclude is defined, but contains an empty set

    NullArgumentException if either tagsToInclude or tagsToExclude are null

  49. class Finders extends Annotation with Annotation with ClassfileAnnotation

    Permalink
  50. trait FixtureContext extends scalatest.compatible.Assertion

    Permalink

    Marker trait for fixture-context objects, that enables them to be used in testing styles that require type Assertion

    Marker trait for fixture-context objects, that enables them to be used in testing styles that require type Assertion

    A fixture-context object is a way to share fixtures between different tests that is most useful when different tests need different combinations of fixture objects. The fixture-context object technique is only appropriate if you don't need to clean up the fixtures after using them.

    To use this technique, you define instance variables intialized with fixture objects in traits and/or classes, then in each test instantiate an object that contains just the fixture objects needed by the test. Traits allow you to mix together just the fixture objects needed by each test, whereas classes allow you to pass data in via a constructor to configure the fixture objects. Here's an example FlatSpec in which fixture objects are partitioned into two traits and each test just mixes together the traits it needs:

    package org.scalatest.examples.flatspec.fixturecontext
    
    import collection.mutable.ListBuffer
    import org.scalatest.FlatSpec
    import org.scalatest.FixtureContext
    
    class ExampleSpec extends FlatSpec {
    
      trait Builder extends FixtureContext {
        val builder = new StringBuilder("ScalaTest is ")
      }
    
      trait Buffer extends FixtureContext {
        val buffer = ListBuffer("ScalaTest", "is")
      }
    
      // This test needs the StringBuilder fixture
      "Testing" should "be productive" in new Builder {
        builder.append("productive!")
        assert(builder.toString === "ScalaTest is productive!")
      }
    
      // This test needs the ListBuffer[String] fixture
      "Test code" should "be readable" in new Buffer {
        buffer += ("readable!")
        assert(buffer === List("ScalaTest", "is", "readable!"))
      }
    
      // This test needs both the StringBuilder and ListBuffer
      it should "be clear and concise" in new Builder with Buffer {
        builder.append("clear!")
        buffer += ("concise!")
        assert(builder.toString === "ScalaTest is clear!")
        assert(buffer === List("ScalaTest", "is", "concise!"))
      }
    }
    

    Extending FixtureContext, which extends trait org.scalatest.compatible.Assertion makes it more convenient to use fixture-context objects in styles, such as async styles, that require test bodies to have type Assertion.

  51. class FlatSpec extends FlatSpecLike

    Permalink

    Facilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.

    Facilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.

    Recommended Usage: Class FlatSpec is a good first step for teams wishing to move from xUnit to BDD, because its structure is flat like xUnit, so simple and familiar, but the test names must be written in a specification style: “X should Y,” “A must B,” etc.

    Trait FlatSpec is so named because your specification text and tests line up flat against the left-side indentation level, with no nesting needed. Here's an example FlatSpec:

    package org.scalatest.examples.flatspec
    
    import org.scalatest.FlatSpec
    
    class SetSpec extends FlatSpec {
    
      behavior of "An empty Set"
    
      it should "have size 0" in {
        assert(Set.empty.size === 0)
      }
    
      it should "produce NoSuchElementException when head is invoked" in {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
    

    Note: you can use must or can as well as should in a FlatSpec. For example, instead of it should "have..., you could write it must "have... or it can "have....

    Instead of using a behavior of clause, you can alternatively use a shorthand syntax in which you replace the first it with the subject string, like this:

    package org.scalatest.examples.flatspec
    
    import org.scalatest.FlatSpec
    
    class SetSpec extends FlatSpec {
    
      "An empty Set" should "have size 0" in {
        assert(Set.empty.size === 0)
      }
    
      it should "produce NoSuchElementException when head is invoked" in {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
    

    Running either of the two previous versions of SetSpec in the Scala interpreter would yield:

    An empty Set
    - should have size 0
    - should produce NoSuchElementException when head is invoked
    

    In a FlatSpec you write a one (or more) sentence specification for each bit of behavior you wish to specify and test. Each specification sentence has a "subject," which is sometimes called the system under test (or SUT). The subject is the entity being specified and tested and also serves as the subject of the sentences you write for each test. Often you will want to write multiple tests for the same subject. In a FlatSpec, you name the subject once, with a behavior of clause or its shorthand, then write tests for that subject with it should/must/can "do something" phrases. Each it refers to the most recently declared subject. For example, the four tests shown in this snippet are all testing a stack that contains one item:

    behavior of "A Stack (with one item)"
    
    it should "be non-empty" in {}
    
    it should "return the top item on peek" in {}
    
    it should "not remove the top item on peek" in {}
    
    it should "remove the top item on pop" in {}
    

    The same is true if the tests are written using the shorthand notation:

    "A Stack (with one item)" should "be non-empty" in {}
    
    it should "return the top item on peek" in {}
    
    it should "not remove the top item on peek" in {}
    
    it should "remove the top item on pop" in {}
    

    In a FlatSpec, therefore, to figure out what "it" means, you just scan vertically until you find the most recent use of behavior of or the shorthand notation.

    Because sometimes the subject could be plural, you can alternatively use they instead of it:

    "The combinators" should "be easy to learn" in {}
    
    they should "be efficient" in {}
    
    they should "do something cool" in {}
    

    A FlatSpec's lifecycle has two phases: the registration phase and the ready phase. It starts in registration phase and enters ready phase the first time run is called on it. It then remains in ready phase for the remainder of its lifetime.

    Tests can only be registered while the FlatSpec is in its registration phase. Any attempt to register a test after the FlatSpec has entered its ready phase, i.e., after run has been invoked on the FlatSpec, will be met with a thrown TestRegistrationClosedException. The recommended style of using FlatSpec is to register tests during object construction as is done in all the examples shown here. If you keep to the recommended style, you should never see a TestRegistrationClosedException.

    Ignored tests

    To support the common use case of temporarily disabling a test, with the good intention of resurrecting the test at a later time, FlatSpec provides a method ignore that can be used instead of it or they to register a test. For example, to temporarily disable the test with the name "An empty Set should produce NoSuchElementException when head is invoked", just change “it” into “ignore,” like this:

    package org.scalatest.examples.flatspec.ignore
    
    import org.scalatest.FlatSpec
    
    class SetSpec extends FlatSpec {
    
      "An empty Set" should "have size 0" in {
        assert(Set.empty.size === 0)
      }
    
      ignore should "produce NoSuchElementException when head is invoked" in {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
    

    If you run this version of SetSpec with:

    scala> org.scalatest.run(new SetSpec)
    

    It will run only the first test and report that the second test was ignored:

    An empty Set
    - should have size 0
    - should produce NoSuchElementException when head is invoked !!! IGNORED !!!
    

    When using shorthand notation, you won't have an it to change into ignore for the first test of each new subject. To ignore such tests, you must instead change in to ignore. For example, to temporarily disable the test with the name "An empty Set should have size 0", change “in” into “ignore” like this:

    package org.scalatest.examples.flatspec.ignoreafter
    
    import org.scalatest.FlatSpec
    
    class SetSpec extends FlatSpec {
    
      "An empty Set" should "have size 0" ignore {
        assert(Set.empty.size === 0)
      }
    
      it should "produce NoSuchElementException when head is invoked" in {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
    

    If you run this version of StackSpec with:

    scala> org.scalatest.run(new SetSpec)
    

    It will run only the second test and report that the first test was ignored:

    An empty Set
    - should have size 0 !!! IGNORED !!!
    - should produce NoSuchElementException when head is invoked
    

    If you wish to temporarily ignore an entire suite of tests, you can (on the JVM, not Scala.js) annotate the test class with @Ignore, like this:

    package org.scalatest.examples.flatspec.ignoreall
    
    import org.scalatest._
    
    @Ignore
    class SetSpec extends FlatSpec {
    
      "An empty Set" should "have size 0" in {
        assert(Set.empty.size === 0)
      }
    
      it should "produce NoSuchElementException when head is invoked" in {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
    

    When you mark a test class with a tag annotation, ScalaTest will mark each test defined in that class with that tag. Thus, marking the SetSpec in the above example with the @Ignore tag annotation means that both tests in the class will be ignored. If you run the above SetSpec in the Scala interpreter, you'll see:

    scala> org.scalatest.run(new SetSpec)
    SetSpec:
    An empty Set
    - should have size 0 !!! IGNORED !!!
    - should produce NoSuchElementException when head is invoked !!! IGNORED !!!
    

    Note that marking a test class as ignored won't prevent it from being discovered by ScalaTest. Ignored classes will be discovered and run, and all their tests will be reported as ignored. This is intended to keep the ignored class visible, to encourage the developers to eventually fix and “un-ignore” it. If you want to prevent a class from being discovered at all (on the JVM, not Scala.js), use the DoNotDiscover annotation instead.

    Informers

    One of the parameters to FlatSpec's run method is a Reporter, which will collect and report information about the running suite of tests. Information about suites and tests that were run, whether tests succeeded or failed, and tests that were ignored will be passed to the Reporter as the suite runs. Most often the reporting done by default by FlatSpec's methods will be sufficient, but occasionally you may wish to provide custom information to the Reporter from a test. For this purpose, an Informer that will forward information to the current Reporter is provided via the info parameterless method. You can pass the extra information to the Informer via its apply method. The Informer will then pass the information to the Reporter via an InfoProvided event.

    One use case for the Informer is to pass more information about a specification to the reporter. For example, the GivenWhenThen trait provides methods that use the implicit info provided by FlatSpec to pass such information to the reporter. Here's an example:

    package org.scalatest.examples.flatspec.info
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends FlatSpec with GivenWhenThen {
    
      "A mutable Set" should "allow an element to be added" in {
        Given("an empty mutable Set")
        val set = mutable.Set.empty[String]
    
        When("an element is added")
        set += "clarity"
    
        Then("the Set should have size 1")
        assert(set.size === 1)
    
        And("the Set should contain the added element")
        assert(set.contains("clarity"))
    
        info("That's all folks!")
      }
    }
    

    If you run this FlatSpec from the interpreter, you will see the following output:

    scala> org.scalatest.run(new SetSpec)
    SetSpec:
    A mutable Set
    - should allow an element to be added
      + Given an empty mutable Set
      + When an element is added
      + Then the Set should have size 1
      + And the Set should contain the added element
      + That's all folks! 
    

    Documenters

    FlatSpec also provides a markup method that returns a Documenter, which allows you to send to the Reporter text formatted in Markdown syntax. You can pass the extra information to the Documenter via its apply method. The Documenter will then pass the information to the Reporter via an MarkupProvided event.

    Here's an example FlatSpec that uses markup:

    package org.scalatest.examples.flatspec.markup
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends FlatSpec with GivenWhenThen {
    
      markup { """
    
    Mutable Set
    -----------
    
    A set is a collection that contains no duplicate elements.
    
    To implement a concrete mutable set, you need to provide implementations
    of the following methods:
    
        def contains(elem: A): Boolean
        def iterator: Iterator[A]
        def += (elem: A): this.type
        def -= (elem: A): this.type
    
    If you wish that methods like `take`,
    `drop`, `filter` return the same kind of set,
    you should also override:
    
        def empty: This
    
    It is also good idea to override methods `foreach` and
    `size` for efficiency.
    
      """ }
    
      "A mutable Set" should "allow an element to be added" in {
        Given("an empty mutable Set")
        val set = mutable.Set.empty[String]
    
        When("an element is added")
        set += "clarity"
    
        Then("the Set should have size 1")
        assert(set.size === 1)
    
        And("the Set should contain the added element")
        assert(set.contains("clarity"))
    
        markup("This test finished with a **bold** statement!")
      }
    }
    

    Although all of ScalaTest's built-in reporters will display the markup text in some form, the HTML reporter will format the markup information into HTML. Thus, the main purpose of markup is to add nicely formatted text to HTML reports. Here's what the above SetSpec would look like in the HTML reporter:

    Notifiers and alerters

    ScalaTest records text passed to info and markup during tests, and sends the recorded text in the recordedEvents field of test completion events like TestSucceeded and TestFailed. This allows string reporters (like the standard out reporter) to show info and markup text after the test name in a color determined by the outcome of the test. For example, if the test fails, string reporters will show the info and markup text in red. If a test succeeds, string reporters will show the info and markup text in green. While this approach helps the readability of reports, it means that you can't use info to get status updates from long running tests.

    To get immediate (i.e., non-recorded) notifications from tests, you can use note (a Notifier) and alert (an Alerter). Here's an example showing the differences:

    package org.scalatest.examples.flatspec.note
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends FlatSpec {
    
      "A mutable Set" should "allow an element to be added" in {
    
        info("info is recorded")
        markup("markup is *also* recorded")
        note("notes are sent immediately")
        alert("alerts are also sent immediately")
    
        val set = mutable.Set.empty[String]
        set += "clarity"
        assert(set.size === 1)
        assert(set.contains("clarity"))
      }
    }
    

    Because note and alert information is sent immediately, it will appear before the test name in string reporters, and its color will be unrelated to the ultimate outcome of the test: note text will always appear in green, alert text will always appear in yellow. Here's an example:

    scala> org.scalatest.run(new SetSpec)
    SetSpec:
    A mutable Set
      + notes are sent immediately
      + alerts are also sent immediately
    - should allow an element to be added
      + info is recorded
      + markup is *also* recorded
    

    Another example is slowpoke notifications. If you find a test is taking a long time to complete, but you're not sure which test, you can enable slowpoke notifications. ScalaTest will use an Alerter to fire an event whenever a test has been running longer than a specified amount of time.

    In summary, use info and markup for text that should form part of the specification output. Use note and alert to send status notifications. (Because the HTML reporter is intended to produce a readable, printable specification, info and markup text will appear in the HTML report, but note and alert text will not.)

    Pending tests

    A pending test is one that has been given a name but is not yet implemented. The purpose of pending tests is to facilitate a style of testing in which documentation of behavior is sketched out before tests are written to verify that behavior (and often, before the behavior of the system being tested is itself implemented). Such sketches form a kind of specification of what tests and functionality to implement later.

    To support this style of testing, a test can be given a name that specifies one bit of behavior required by the system being tested. The test can also include some code that sends more information about the behavior to the reporter when the tests run. At the end of the test, it can call method pending, which will cause it to complete abruptly with TestPendingException.

    Because tests in ScalaTest can be designated as pending with TestPendingException, both the test name and any information sent to the reporter when running the test can appear in the report of a test run. (In other words, the code of a pending test is executed just like any other test.) However, because the test completes abruptly with TestPendingException, the test will be reported as pending, to indicate the actual test, and possibly the functionality it is intended to test, has not yet been implemented. You can mark tests as pending in FlatSpec like this:

    package org.scalatest.examples.flatspec.pending
    
    import org.scalatest._
    
    class SetSpec extends FlatSpec {
    
      "An empty Set" should "have size 0" in (pending)
    
      it should "produce NoSuchElementException when head is invoked" in {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
    

    If you run this version of FlatSpec with:

    scala> org.scalatest.run(new SetSpec)
    

    It will run both tests but report that An empty Set should have size 0 is pending. You'll see:

    An empty Set
    - should have size 0 (pending)
    - should produce NoSuchElementException when head is invoked
    

    One difference between an ignored test and a pending one is that an ignored test is intended to be used during a significant refactorings of the code under test, when tests break and you don't want to spend the time to fix all of them immediately. You can mark some of those broken tests as ignored temporarily, so that you can focus the red bar on just failing tests you actually want to fix immediately. Later you can go back and fix the ignored tests. In other words, by ignoring some failing tests temporarily, you can more easily notice failed tests that you actually want to fix. By contrast, a pending test is intended to be used before a test and/or the code under test is written. Pending indicates you've decided to write a test for a bit of behavior, but either you haven't written the test yet, or have only written part of it, or perhaps you've written the test but don't want to implement the behavior it tests until after you've implemented a different bit of behavior you realized you need first. Thus ignored tests are designed to facilitate refactoring of existing code whereas pending tests are designed to facilitate the creation of new code.

    One other difference between ignored and pending tests is that ignored tests are implemented as a test tag that is excluded by default. Thus an ignored test is never executed. By contrast, a pending test is implemented as a test that throws TestPendingException (which is what calling the pending method does). Thus the body of pending tests are executed up until they throw TestPendingException. The reason for this difference is that it enables your unfinished test to send InfoProvided messages to the reporter before it completes abruptly with TestPendingException, as shown in the previous example on Informers that used the GivenWhenThen trait. For example, the following snippet in a FlatSpec:

     "The Scala language" must "add correctly" in {
        Given("two integers")
        When("they are added")
        Then("the result is the sum of the two numbers")
        pending
      }
      // ...
    

    Would yield the following output when run in the interpreter:

    The Scala language
    - must add correctly (pending)
      + Given two integers
      + When they are added
      + Then the result is the sum of the two numbers
    

    Tagging tests

    A FlatSpec's tests may be classified into groups by tagging them with string names. As with any suite, when executing a FlatSpec, groups of tests can optionally be included and/or excluded. To tag a FlatSpec's tests, you pass objects that extend class org.scalatest.Tag to methods that register tests. Class Tag takes one parameter, a string name. If you have created tag annotation interfaces as described in the Tag documentation, then you will probably want to use tag names on your test functions that match. To do so, simply pass the fully qualified names of the tag interfaces to the Tag constructor. For example, if you've defined a tag annotation interface with fully qualified name, com.mycompany.tags.DbTest, then you could create a matching tag for FlatSpecs like this:

    package org.scalatest.examples.flatspec.tagging
    
    import org.scalatest.Tag
    
    object DbTest extends Tag("com.mycompany.tags.DbTest")
    

    Given these definitions, you could place FlatSpec tests into groups with tags like this:

    import org.scalatest.FlatSpec
    import org.scalatest.tagobjects.Slow
    
    class SetSpec extends FlatSpec {
    
      behavior of "An empty Set"
    
      it should "have size 0" taggedAs(Slow) in {
        assert(Set.empty.size === 0)
      }
    
      it should "produce NoSuchElementException when head is invoked" taggedAs(Slow, DbTest) in {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
    

    This code marks both tests with the org.scalatest.tags.Slow tag, and the second test with the com.mycompany.tags.DbTest tag.

    The run method takes a Filter, whose constructor takes an optional Set[String] called tagsToInclude and a Set[String] called tagsToExclude. If tagsToInclude is None, all tests will be run except those those belonging to tags listed in the tagsToExclude Set. If tagsToInclude is defined, only tests belonging to tags mentioned in the tagsToInclude set, and not mentioned in tagsToExclude, will be run.

    It is recommended, though not required, that you create a corresponding tag annotation when you create a Tag object. A tag annotation (on the JVM, not Scala.js) allows you to tag all the tests of a FlatSpec in one stroke by annotating the class. For more information and examples, see the documentation for class Tag. On Scala.js, to tag all tests of a suite, you'll need to tag each test individually at the test site.

    Shared fixtures

    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.

    ScalaTest recommends three techniques to eliminate such code duplication:

    • Refactor using Scala
    • Override withFixture
    • Mix in a before-and-after trait

    Each technique is geared towards helping you reduce code duplication without introducing instance vars, shared mutable objects, or other dependencies between tests. Eliminating shared mutable state across tests will make your test code easier to reason about and more amenable for parallel test execution.

    The following sections describe these techniques, including explaining the recommended usage for each. But first, here's a table summarizing the options:

    Refactor using Scala when different tests need different fixtures.
    get-fixture methods The extract method refactor helps you create a fresh instances of mutable fixture objects in each test that needs them, but doesn't help you clean them up when you're done.
    fixture-context objects By placing fixture methods and fields into traits, you can easily give each test just the newly created fixtures it needs by mixing together traits. Use this technique when you need different combinations of mutable fixture objects in different tests, and don't need to clean up after.
    loan-fixture methods Factor out dupicate code with the loan pattern when different tests need different fixtures that must be cleaned up afterwards.
    Override withFixture when most or all tests need the same fixture.
    withFixture(NoArgTest) The recommended default approach when most or all tests need the same fixture treatment. This general technique allows you, for example, to perform side effects at the beginning and end of all or most tests, transform the outcome of tests, retry tests, make decisions based on test names, tags, or other test data. Use this technique unless:
    Different tests need different fixtures (refactor using Scala instead)
    An exception in fixture code should abort the suite, not fail the test (use a before-and-after trait instead)
    You have objects to pass into tests (override withFixture(OneArgTest) instead)
    withFixture(OneArgTest) Use when you want to pass the same fixture object or objects as a parameter into all or most tests.
    Mix in a before-and-after trait when you want an aborted suite, not a failed test, if the fixture code fails.
    BeforeAndAfter Use this boilerplate-buster when you need to perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.
    BeforeAndAfterEach Use when you want to stack traits that perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.

    Calling get-fixture methods

    If you need to create the same mutable fixture objects in multiple tests, and don't need to clean them up after using them, the simplest approach is to write one or more get-fixture methods. A get-fixture method returns a new instance of a needed fixture object (or a holder object containing multiple fixture objects) each time it is called. You can call a get-fixture method at the beginning of each test that needs the fixture, storing the returned object or objects in local variables. Here's an example:

    package org.scalatest.examples.flatspec.getfixture
    
    import org.scalatest.FlatSpec
    import collection.mutable.ListBuffer
    
    class ExampleSpec extends FlatSpec {
    
      class Fixture {
        val builder = new StringBuilder("ScalaTest is ")
        val buffer = new ListBuffer[String]
      }
    
      def fixture = new Fixture
    
      "Testing" should "be easy" in {
        val f = fixture
        f.builder.append("easy!")
        assert(f.builder.toString === "ScalaTest is easy!")
        assert(f.buffer.isEmpty)
        f.buffer += "sweet"
      }
    
      it should "be fun" in {
        val f = fixture
        f.builder.append("fun!")
        assert(f.builder.toString === "ScalaTest is fun!")
        assert(f.buffer.isEmpty)
      }
    }
    

    The “f.” in front of each use of a fixture object provides a visual indication of which objects are part of the fixture, but if you prefer, you can import the the members with “import f._” and use the names directly.

    If you need to configure fixture objects differently in different tests, you can pass configuration into the get-fixture method. For example, if you could pass in an initial value for a mutable fixture object as a parameter to the get-fixture method.

    Instantiating fixture-context objects

    An alternate technique that is especially useful when different tests need different combinations of fixture objects is to define the fixture objects as instance variables of fixture-context objects whose instantiation forms the body of tests. Like get-fixture methods, fixture-context objects are only appropriate if you don't need to clean up the fixtures after using them.

    To use this technique, you define instance variables intialized with fixture objects in traits and/or classes, then in each test instantiate an object that contains just the fixture objects needed by the test. Traits allow you to mix together just the fixture objects needed by each test, whereas classes allow you to pass data in via a constructor to configure the fixture objects. Here's an example in which fixture objects are partitioned into two traits and each test just mixes together the traits it needs:

    package org.scalatest.examples.flatspec.fixturecontext
    
    import collection.mutable.ListBuffer
    import org.scalatest.FlatSpec
    
    class ExampleSpec extends FlatSpec {
    
      trait Builder {
        val builder = new StringBuilder("ScalaTest is ")
      }
    
      trait Buffer {
        val buffer = ListBuffer("ScalaTest", "is")
      }
    
      // This test needs the StringBuilder fixture
      "Testing" should "be productive" in new Builder {
        builder.append("productive!")
        assert(builder.toString === "ScalaTest is productive!")
      }
    
      // This test needs the ListBuffer[String] fixture
      "Test code" should "be readable" in new Buffer {
        buffer += ("readable!")
        assert(buffer === List("ScalaTest", "is", "readable!"))
      }
    
      // This test needs both the StringBuilder and ListBuffer
      it should "be clear and concise" in new Builder with Buffer {
        builder.append("clear!")
        buffer += ("concise!")
        assert(builder.toString === "ScalaTest is clear!")
        assert(buffer === List("ScalaTest", "is", "concise!"))
      }
    }
    

    Overriding withFixture(NoArgTest)

    Although the get-fixture method and fixture-context object approaches take care of setting up a fixture at the beginning of each test, they don't address the problem of cleaning up a fixture at the end of the test. If you just need to perform a side-effect at the beginning or end of a test, and don't need to actually pass any fixture objects into the test, you can override withFixture(NoArgTest), one of ScalaTest's lifecycle methods defined in trait Suite.

    Trait Suite's implementation of runTest passes a no-arg test function to withFixture(NoArgTest). It is withFixture's responsibility to invoke that test function. Suite's implementation of withFixture simply invokes the function, like this:

    // Default implementation in trait Suite
    protected def withFixture(test: NoArgTest) = {
      test()
    }
    

    You can, therefore, override withFixture to perform setup before and/or cleanup after invoking the test function. If you have cleanup to perform, you should invoke the test function inside a try block and perform the cleanup in a finally clause, in case an exception propagates back through withFixture. (If a test fails because of an exception, the test function invoked by withFixture will result in a Failed wrapping the exception. Nevertheless, best practice is to perform cleanup in a finally clause just in case an exception occurs.)

    The withFixture method is designed to be stacked, and to enable this, you should always call the super implementation of withFixture, and let it invoke the test function rather than invoking the test function directly. That is to say, instead of writing “test()”, you should write “super.withFixture(test)”, like this:

    // Your implementation
    override def withFixture(test: NoArgTest) = {
      // Perform setup
      try super.withFixture(test) // Invoke the test function
      finally {
        // Perform cleanup
      }
    }
    

    Here's an example in which withFixture(NoArgTest) is used to take a snapshot of the working directory if a test fails, and send that information to the reporter:

    package org.scalatest.examples.flatspec.noargtest
    
    import java.io.File
    import org.scalatest._
    
    class ExampleSpec extends FlatSpec {
    
      override def withFixture(test: NoArgTest) = {
    
        super.withFixture(test) match {
          case failed: Failed =>
            val currDir = new File(".")
            val fileNames = currDir.list()
            info("Dir snapshot: " + fileNames.mkString(", "))
            failed
          case other => other
        }
      }
    
      "This test" should "succeed" in {
        assert(1 + 1 === 2)
      }
    
      it should "fail" in {
        assert(1 + 1 === 3)
      }
    }
    

    Running this version of ExampleSuite in the interpreter in a directory with two files, hello.txt and world.txt would give the following output:

    scala> org.scalatest.run(new ExampleSuite)
    ExampleSuite:
    This test
    - should succeed
    - should fail *** FAILED ***
      2 did not equal 3 (:33)
      + Dir snapshot: hello.txt, world.txt 
    

    Note that the NoArgTest passed to withFixture, in addition to an apply method that executes the test, also includes TestData such as the test name and the config map passed to runTest. Thus you can also use the test name and configuration objects in your withFixture implementation.

    Calling loan-fixture methods

    If you need to both pass a fixture object into a test and perform cleanup at the end of the test, you'll need to use the loan pattern. If different tests need different fixtures that require cleanup, you can implement the loan pattern directly by writing loan-fixture methods. A loan-fixture method takes a function whose body forms part or all of a test's code. It creates a fixture, passes it to the test code by invoking the function, then cleans up the fixture after the function returns.

    The following example shows three tests that use two fixtures, a database and a file. Both require cleanup after, so each is provided via a loan-fixture method. (In this example, the database is simulated with a StringBuffer.)

    package org.scalatest.examples.flatspec.loanfixture
    
    import java.util.concurrent.ConcurrentHashMap
    
    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)
      }
    }
    
    import org.scalatest.FlatSpec
    import DbServer._
    import java.util.UUID.randomUUID
    import java.io._
    
    class ExampleSpec extends FlatSpec {
    
      def withDatabase(testCode: Db => Any) {
        val dbName = randomUUID.toString
        val db = createDb(dbName) // create the fixture
        try {
          db.append("ScalaTest is ") // perform setup
          testCode(db) // "loan" the fixture to the test
        }
        finally removeDb(dbName) // clean up the fixture
      }
    
      def withFile(testCode: (File, FileWriter) => Any) {
        val file = File.createTempFile("hello", "world") // create the fixture
        val writer = new FileWriter(file)
        try {
          writer.write("ScalaTest is ") // set up the fixture
          testCode(file, writer) // "loan" the fixture to the test
        }
        finally writer.close() // clean up the fixture
      }
    
      // This test needs the file fixture
      "Testing" should "be productive" in withFile { (file, writer) =>
        writer.write("productive!")
        writer.flush()
        assert(file.length === 24)
      }
    
      // This test needs the database fixture
      "Test code" should "be readable" in withDatabase { db =>
        db.append("readable!")
        assert(db.toString === "ScalaTest is readable!")
      }
    
      // This test needs both the file and the database
      it should "be clear and concise" in withDatabase { db =>
        withFile { (file, writer) => // loan-fixture methods compose
          db.append("clear!")
          writer.write("concise!")
          writer.flush()
          assert(db.toString === "ScalaTest is clear!")
          assert(file.length === 21)
        }
      }
    }
    

    As demonstrated by the last test, loan-fixture methods compose. Not only do loan-fixture methods allow you to give each test the fixture it needs, they allow you to give a test multiple fixtures and clean everything up afterwards.

    Also demonstrated in this example is 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 this example. This keeps tests completely isolated, allowing you to run them in parallel if desired.

    Overriding withFixture(OneArgTest)

    If all or most tests need the same fixture, you can avoid some of the boilerplate of the loan-fixture method approach by using a fixture.FlatSpec and overriding withFixture(OneArgTest). Each test in a fixture.FlatSpec takes a fixture as a parameter, allowing you to pass the fixture into the test. You must indicate the type of the fixture parameter by specifying FixtureParam, and implement a withFixture method that takes a OneArgTest. This withFixture method is responsible for invoking the one-arg test function, so you can perform fixture set up before, and clean up after, invoking and passing the fixture into the test function.

    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) = {
        val file = File.createTempFile("hello", "world") // create the fixture
        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)
      }
    }
    

    In this example, the tests actually required two fixture objects, a File and a FileWriter. In such situations you can simply define the FixtureParam type to be a tuple containing the objects, or as is done in this example, a case class containing the objects. For more information on the withFixture(OneArgTest) technique, see the documentation for fixture.FlatSpec.

    Mixing in BeforeAndAfter

    In all the shared fixture examples shown so far, the activities of creating, setting up, and cleaning up the fixture objects have been performed during the test. This means that if an exception occurs during any of these activities, it will be reported as a test failure. Sometimes, however, you may want setup to happen before the test starts, and cleanup after the test has completed, so that if an exception occurs during setup or cleanup, the entire suite aborts and no more tests are attempted. The simplest way to accomplish this in ScalaTest is to mix in trait BeforeAndAfter. With this trait you can denote a bit of code to run before each test with before and/or after each test each test with after, like this:

    package org.scalatest.examples.flatspec.beforeandafter
    
    import org.scalatest._
    import collection.mutable.ListBuffer
    
    class ExampleSpec extends FlatSpec with BeforeAndAfter {
    
      val builder = new StringBuilder
      val buffer = new ListBuffer[String]
    
      before {
        builder.append("ScalaTest is ")
      }
    
      after {
        builder.clear()
        buffer.clear()
      }
    
      "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)
      }
    }
    

    Note that the only way before and after code can communicate with test code is via some side-effecting mechanism, commonly by reassigning instance vars or by changing the state of mutable objects held from instance vals (as in this example). If using instance vars or mutable objects held from instance vals you wouldn't be able to run tests in parallel in the same instance of the test class (on the JVM, not Scala.js) unless you synchronized access to the shared, mutable state. This is why ScalaTest's ParallelTestExecution trait extends OneInstancePerTest. By running each test in its own instance of the class, each test has its own copy of the instance variables, so you don't need to synchronize. If you mixed ParallelTestExecution into the ExampleSuite above, the tests would run in parallel just fine without any synchronization needed on the mutable StringBuilder and ListBuffer[String] objects.

    Although BeforeAndAfter provides a minimal-boilerplate way to execute code before and after tests, it isn't designed to enable stackable traits, because the order of execution would be non-obvious. If you want to factor out before and after code that is common to multiple test suites, you should use trait BeforeAndAfterEach instead, as shown later in the next section, composing fixtures by stacking traits.

    Composing fixtures by stacking traits

    In larger projects, teams often end up with several different fixtures that test classes need in different combinations, and possibly initialized (and cleaned up) in different orders. A good way to accomplish this in ScalaTest is to factor the individual fixtures into traits that can be composed using the stackable trait pattern. This can be done, for example, by placing withFixture methods in several traits, each of which call super.withFixture. Here's an example in which the StringBuilder and ListBuffer[String] fixtures used in the previous examples have been factored out into two stackable fixture traits named Builder and Buffer:

    package org.scalatest.examples.flatspec.composingwithfixture
    
    import org.scalatest._
    import collection.mutable.ListBuffer
    
    trait Builder extends TestSuiteMixin { this: TestSuite =>
    
      val builder = new StringBuilder
    
      abstract override def withFixture(test: NoArgTest) = {
        builder.append("ScalaTest is ")
        try super.withFixture(test) // To be stackable, must call super.withFixture
        finally builder.clear()
      }
    }
    
    trait Buffer extends TestSuiteMixin { this: TestSuite =>
    
      val buffer = new ListBuffer[String]
    
      abstract override def withFixture(test: NoArgTest) = {
        try super.withFixture(test) // To be stackable, must call super.withFixture
        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"
      }
    }
    

    By mixing in both the Builder and Buffer traits, ExampleSuite gets both fixtures, which will be initialized before each test and cleaned up after. The order the traits are mixed together determines the order of execution. In this case, Builder is “super” to Buffer. If you wanted Buffer to be “super” to Builder, you need only switch the order you mix them together, like this:

    class Example2Spec extends FlatSpec with Buffer with Builder
    

    And if you only need one fixture you mix in only that trait:

    class Example3Spec extends FlatSpec with Builder
    

    Another way to create stackable fixture traits is by extending the BeforeAndAfterEach and/or BeforeAndAfterAll traits. BeforeAndAfterEach has 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). Similarly, BeforeAndAfterAll has a beforeAll method that will be run before all tests, and an afterAll method that will be run after all tests. Here's what the previously shown example would look like if it were rewritten to use the BeforeAndAfterEach methods instead of withFixture:

    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 difference between stacking traits that extend BeforeAndAfterEach versus traits that implement withFixture is that setup and cleanup code happens before and after the test in BeforeAndAfterEach, but at the beginning and end of the test in withFixture. Thus if a withFixture method completes abruptly with an exception, it is considered a failed test. By contrast, if any of the beforeEach or afterEach methods of BeforeAndAfterEach complete abruptly, it is considered an aborted suite, which will result in a SuiteAborted event.

    Shared tests

    Sometimes you may want to run the same test code on different fixture objects. In other words, you may want to write tests that are "shared" by different fixture objects. To accomplish this in a FlatSpec, you first place shared tests in behavior functions. These behavior functions will be invoked during the construction phase of any FlatSpec that uses them, so that the tests they contain will be registered as tests in that FlatSpec. For example, given this stack class:

    import scala.collection.mutable.ListBuffer
    
    class Stack[T] {
    
      val MAX = 10
      private val buf = new ListBuffer[T]
    
      def push(o: T) {
        if (!full)
          buf.prepend(o)
        else
          throw new IllegalStateException("can't push onto a full stack")
      }
    
      def pop(): T = {
        if (!empty)
          buf.remove(0)
        else
          throw new IllegalStateException("can't pop an empty stack")
      }
    
      def peek: T = {
        if (!empty)
          buf(0)
        else
          throw new IllegalStateException("can't pop an empty stack")
      }
    
      def full: Boolean = buf.size == MAX
      def empty: Boolean = buf.size == 0
      def size = buf.size
    
      override def toString = buf.mkString("Stack(", ", ", ")")
    }
    

    You may want to test the Stack class in different states: empty, full, with one item, with one item less than capacity, etc. You may find you have several tests that make sense any time the stack is non-empty. Thus you'd ideally want to run those same tests for three stack fixture objects: a full stack, a stack with a one item, and a stack with one item less than capacity. With shared tests, you can factor these tests out into a behavior function, into which you pass the stack fixture to use when running the tests. So in your FlatSpec for stack, you'd invoke the behavior function three times, passing in each of the three stack fixtures so that the shared tests are run for all three fixtures. You can define a behavior function that encapsulates these shared tests inside the FlatSpec that uses them. If they are shared between different FlatSpecs, however, you could also define them in a separate trait that is mixed into each FlatSpec that uses them.

    For example, here the nonEmptyStack behavior function (in this case, a behavior method) is defined in a trait along with another method containing shared tests for non-full stacks:

    trait StackBehaviors { this: FlatSpec =>
    
      def nonEmptyStack(newStack: => Stack[Int], lastItemAdded: Int) {
    
        it should "be non-empty" in {
          assert(!newStack.empty)
        }
    
        it should "return the top item on peek" in {
          assert(newStack.peek === lastItemAdded)
        }
    
        it should "not remove the top item on peek" in {
          val stack = newStack
          val size = stack.size
          assert(stack.peek === lastItemAdded)
          assert(stack.size === size)
        }
    
        it should "remove the top item on pop" in {
          val stack = newStack
          val size = stack.size
          assert(stack.pop === lastItemAdded)
          assert(stack.size === size - 1)
        }
      }
    
      def nonFullStack(newStack: => Stack[Int]) {
    
        it should "not be full" in {
          assert(!newStack.full)
        }
    
        it should "add to the top on push" in {
          val stack = newStack
          val size = stack.size
          stack.push(7)
          assert(stack.size === size + 1)
          assert(stack.peek === 7)
        }
      }
    }
    

    Given these behavior functions, you could invoke them directly, but FlatSpec offers a DSL for the purpose, which looks like this:

    it should behave like nonEmptyStack(stackWithOneItem, lastValuePushed)
    it should behave like nonFullStack(stackWithOneItem)
    

    If you prefer to use an imperative style to change fixtures, for example by mixing in BeforeAndAfterEach and reassigning a stack var in beforeEach, you could write your behavior functions in the context of that var, which means you wouldn't need to pass in the stack fixture because it would be in scope already inside the behavior function. In that case, your code would look like this:

    it should behave like nonEmptyStack // assuming lastValuePushed is also in scope inside nonEmptyStack
    it should behave like nonFullStack
    

    The recommended style, however, is the functional, pass-all-the-needed-values-in style. Here's an example:

    class SharedTestExampleSpec extends FlatSpec with StackBehaviors {
    
      // Stack fixture creation methods
      def emptyStack = new Stack[Int]
    
      def fullStack = {
        val stack = new Stack[Int]
        for (i <- 0 until stack.MAX)
          stack.push(i)
        stack
      }
    
      def stackWithOneItem = {
        val stack = new Stack[Int]
        stack.push(9)
        stack
      }
    
      def stackWithOneItemLessThanCapacity = {
        val stack = new Stack[Int]
        for (i <- 1 to 9)
          stack.push(i)
        stack
      }
    
      val lastValuePushed = 9
    
      "A Stack (when empty)" should "be empty" in {
        assert(emptyStack.empty)
      }
    
      it should "complain on peek" in {
        assertThrows[IllegalStateException] {
          emptyStack.peek
        }
      }
    
      it should "complain on pop" in {
        assertThrows[IllegalStateException] {
          emptyStack.pop
        }
      }
    
      "A Stack (with one item)" should behave like nonEmptyStack(stackWithOneItem, lastValuePushed)
    
      it should behave like nonFullStack(stackWithOneItem)
    
      "A Stack (with one item less than capacity)" should behave like nonEmptyStack(stackWithOneItemLessThanCapacity, lastValuePushed)
    
      it should behave like nonFullStack(stackWithOneItemLessThanCapacity)
    
      "A Stack (full)" should "be full" in {
        assert(fullStack.full)
      }
    
      it should behave like nonEmptyStack(fullStack, lastValuePushed)
    
      it should "complain on a push" in {
        assertThrows[IllegalStateException] {
          fullStack.push(10)
        }
      }
    }
    

    If you load these classes into the Scala interpreter (with scalatest's JAR file on the class path), and execute it, you'll see:

    scala> org.scalatest.run(new SharedTestExampleSpec)
    A Stack (when empty)
    - should be empty
    - should complain on peek
    - should complain on pop
    A Stack (with one item)
    - should be non-empty
    - should return the top item on peek
    - should not remove the top item on peek
    - should remove the top item on pop
    - should not be full
    - should add to the top on push
    A Stack (with one item less than capacity)
    - should be non-empty
    - should return the top item on peek
    - should not remove the top item on peek
    - should remove the top item on pop
    - should not be full
    - should add to the top on push
    A Stack (full)
    - should be full
    - should be non-empty
    - should return the top item on peek
    - should not remove the top item on peek
    - should remove the top item on pop
    - should complain on a push
    

    One thing to keep in mind when using shared tests is that in ScalaTest, each test in a suite must have a unique name. If you register the same tests repeatedly in the same suite, one problem you may encounter is an exception at runtime complaining that multiple tests are being registered with the same test name. A good way to solve this problem in a FlatSpec is to make sure each invocation of a behavior function is in the context of a different set of when, verb (should, must, or can), and that clauses, which will prepend a string to each test name. For example, the following code in a FlatSpec would register a test with the name "A Stack (when empty) should be empty":

      behavior of "A Stack (when empty)"
    
      it should "be empty" in {
        assert(emptyStack.empty)
      }
      // ...
    

    Or, using the shorthand notation:

      "A Stack" when {
        "empty" should {
          "be empty" in {
            assert(emptyStack.empty)
          }
        }
      }
      // ...
    

    If the "should be empty" test was factored out into a behavior function, it could be called repeatedly so long as each invocation of the behavior function is in the context of a different combination of when, verb, and that clauses.

    Annotations
    @Finders()
  52. trait FlatSpecLike extends TestSuite with TestRegistration with ShouldVerb with MustVerb with CanVerb with Informing with Notifying with Alerting with Documenting

    Permalink

    Implementation trait for class FlatSpec, which facilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.

    Implementation trait for class FlatSpec, which facilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.

    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 FlatSpec into some other class, you can use this trait instead, because class 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 FlatSpec.

    Annotations
    @Finders() @JSExportDescendentClasses( true )
  53. class FreeSpec extends FreeSpecLike

    Permalink

    Facilitates a “behavior-driven” style of development (BDD), in which tests are nested inside text clauses denoted with the dash operator (-).

    Facilitates a “behavior-driven” style of development (BDD), in which tests are nested inside text clauses denoted with the dash operator (-).

    FreeSpec is so named because unlike classes such as WordSpec, FlatSpec, and FunSpec, it is enforces no structure on the text. You are free to compose text however you like. (A FreeSpec is like free-verse poetry as opposed to a sonnet or haiku, which defines a structure for the text of the poem.)

    Recommended Usage: Because it gives absolute freedom (and no guidance) on how specification text should be written, FreeSpec is a good choice for teams experienced with BDD and able to agree on how to structure the specification text.

    Here's an example FreeSpec:

    package org.scalatest.examples.freespec
    
    import org.scalatest.FreeSpec
    
    class SetSpec extends FreeSpec {
    
      "A Set" - {
        "when empty" - {
          "should have size 0" in {
            assert(Set.empty.size === 0)
          }
    
          "should produce NoSuchElementException when head is invoked" in {
            assertThrows[NoSuchElementException] {
              Set.empty.head
            }
          }
        }
      }
    }
    

    In a FreeSpec you write a test with a string followed by in and the body of the test in curly braces, like this:

    "should have size 0" in {
      // ...
    }
    

    You can nest a test inside any number of description clauses, which you write with a string followed by a dash character and a block, like this:

    "A Set" - {
      // ...
    }
    

    You can nest description clauses as deeply as you want. Because the description clause is denoted with an operator, not a word like should, you are free to structure the text however you wish. Here's an example:

    import org.scalatest.FreeSpec
    
    class StackSpec extends FreeSpec {
      "A Stack" - {
        "whenever it is empty" - {
          "certainly ought to" - {
            "be empty" in {
              // ...
            }
            "complain on peek" in {
              // ...
            }
            "complain on pop" in {
              // ...
            }
          }
        }
        "but when full, by contrast, must" - {
          "be full" in {
            // ...
          }
          "complain on push" in {
            // ...
          }
        }
      }
    }
    

    Running the above StackSpec in the interpreter would yield:

    scala> org.scalatest.run(new StackSpec)
    StackSpec:
    A Stack
      whenever it is empty
        certainly ought to
        - be empty
        - complain on peek
        - complain on pop
      but when full, by contrast, must
      - be full
      - complain on push
    

    A FreeSpec can also be used to write a specification-style test in languages other than English. For example:

    import org.scalatest.FreeSpec
    
    class ComputerRoomRulesSpec extends FreeSpec {
      "Achtung!" - {
        "Alle touristen und non-technischen lookenpeepers!" - {
          "Das machine is nicht fuer fingerpoken und mittengrabben." in {
            // ...
          }
          "Is easy" - {
            "schnappen der springenwerk" in {
              // ...
            }
            "blowenfusen" in {
              // ...
            }
            "und poppencorken mit spitzen sparken." in {
              // ...
            }
          }
          "Das machine is diggen by experten only." in {
            // ...
          }
          "Is nicht fuer gerwerken by das dummkopfen." in {
            // ...
          }
          "Das rubbernecken sightseeren keepen das cottenpicken hands in das pockets." in {
            // ...
          }
          "Relaxen und watchen das blinkenlights." in {
            // ...
          }
        }
      }
    }
    

    Running the above ComputerRoomRulesSpec in the interpreter would yield:

    scala> org.scalatest.run(new ComputerRoomRulesSpec)
    ComputerRoomRulesSpec:
    Achtung!
      Alle touristen und non-technischen lookenpeepers!
      - Das machine is nicht fuer fingerpoken und mittengrabben.
        Is easy
        - schnappen der springenwerk
        - blowenfusen
        - und poppencorken mit spitzen sparken.
      - Das machine is diggen by experten only.
      - Is nicht fuer gerwerken by das dummkopfen.
      - Das rubbernecken sightseeren keepen das cottenpicken hands in das pockets.
      - Relaxen und watchen das blinkenlights.
    

    A FreeSpec's lifecycle has two phases: the registration phase and the ready phase. It starts in registration phase and enters ready phase the first time run is called on it. It then remains in ready phase for the remainder of its lifetime.

    Tests can only be registered while the FreeSpec is in its registration phase. Any attempt to register a test after the FreeSpec has entered its ready phase, i.e., after run has been invoked on the FreeSpec, will be met with a thrown TestRegistrationClosedException. The recommended style of using FreeSpec is to register tests during object construction as is done in all the examples shown here. If you keep to the recommended style, you should never see a TestRegistrationClosedException.

    Ignored tests

    To support the common use case of temporarily disabling a test, with the good intention of resurrecting the test at a later time, FreeSpec adds a method ignore to strings that can be used instead of in to register a test. For example, to temporarily disable the test with the name "A Stack should pop values in last-in-first-out order", just change “in” into “ignore,” like this:

    package org.scalatest.examples.freespec.ignore
    
    import org.scalatest.FreeSpec
    
    class SetSpec extends FreeSpec {
    
      "A Set" - {
        "when empty" - {
          "should have size 0" ignore {
            assert(Set.empty.size === 0)
          }
    
          "should produce NoSuchElementException when head is invoked" in {
            assertThrows[NoSuchElementException] {
              Set.empty.head
            }
          }
        }
      }
    }
    

    If you run this version of SetSpec with:

    scala> org.scalatest.run(new SetSpec)
    

    It will run only the second test and report that the first test was ignored:

    A Set
      when empty
      - should have size 0 !!! IGNORED !!!
      - should produce NoSuchElementException when head is invoked
    

    If you wish to temporarily ignore an entire suite of tests, you can (on the JVM, not Scala.js) annotate the test class with @Ignore, like this:

    package org.scalatest.examples.freespec.ignoreall
    
    import org.scalatest.FreeSpec
    import org.scalatest.Ignore
    
    @Ignore
    class SetSpec extends FreeSpec {
    
      "A Set" - {
        "when empty" - {
          "should have size 0" in {
            assert(Set.empty.size === 0)
          }
    
          "should produce NoSuchElementException when head is invoked" in {
            assertThrows[NoSuchElementException] {
              Set.empty.head
            }
          }
        }
      }
    }
    

    When you mark a test class with a tag annotation, ScalaTest will mark each test defined in that class with that tag. Thus, marking the SetSpec in the above example with the @Ignore tag annotation means that both tests in the class will be ignored. If you run the above SetSpec in the Scala interpreter, you'll see:

    scala> org.scalatest.run(new SetSpec)
    SetSpec:
    A Set
      when empty
      - should have size 0 !!! IGNORED !!!
      - should produce NoSuchElementException when head is invoked !!! IGNORED !!!
    

    Note that marking a test class as ignored won't prevent it from being discovered by ScalaTest. Ignored classes will be discovered and run, and all their tests will be reported as ignored. This is intended to keep the ignored class visible, to encourage the developers to eventually fix and “un-ignore” it. If you want to prevent a class from being discovered at all (on the JVM, not Scala.js), use the DoNotDiscover annotation instead.

    Informers

    One of the parameters to FreeSpec's run method is a Reporter, which will collect and report information about the running suite of tests. Information about suites and tests that were run, whether tests succeeded or failed, and tests that were ignored will be passed to the Reporter as the suite runs. Most often the reporting done by default by FreeSpec's methods will be sufficient, but occasionally you may wish to provide custom information to the Reporter from a test. For this purpose, an Informer that will forward information to the current Reporter is provided via the info parameterless method. You can pass the extra information to the Informer via its apply method. The Informer will then pass the information to the Reporter via an InfoProvided event.

    One use case for the Informer is to pass more information about a specification to the reporter. For example, the GivenWhenThen trait provides methods that use the implicit info provided by FreeSpec to pass such information to the reporter. Here's an example:

    package org.scalatest.examples.freespec.info
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends FreeSpec with GivenWhenThen {
    
      "A mutable Set" - {
        "should allow an element to be added" in {
          Given("an empty mutable Set")
          val set = mutable.Set.empty[String]
    
          When("an element is added")
          set += "clarity"
    
          Then("the Set should have size 1")
          assert(set.size === 1)
    
          And("the Set should contain the added element")
          assert(set.contains("clarity"))
    
          info("That's all folks!")
        }
      }
    }
    

    If you run this FreeSpec from the interpreter, you will see the following output:

    scala> org.scalatest.run(new SetSpec)
    A mutable Set
    - should allow an element to be added
      + Given an empty mutable Set
      + When an element is added
      + Then the Set should have size 1
      + And the Set should contain the added element
      + That's all folks! 
    

    Documenters

    FreeSpec also provides a markup method that returns a Documenter, which allows you to send to the Reporter text formatted in Markdown syntax. You can pass the extra information to the Documenter via its apply method. The Documenter will then pass the information to the Reporter via an MarkupProvided event.

    Here's an example FreeSpec that uses markup:

    package org.scalatest.examples.freespec.markup
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends FreeSpec with GivenWhenThen {
    
      markup { """
    
    Mutable Set
    -----------
    
    A set is a collection that contains no duplicate elements.
    
    To implement a concrete mutable set, you need to provide implementations
    of the following methods:
    
        def contains(elem: A): Boolean
        def iterator: Iterator[A]
        def += (elem: A): this.type
        def -= (elem: A): this.type
    
    If you wish that methods like `take`,
    `drop`, `filter` return the same kind of set,
    you should also override:
    
        def empty: This
    
    It is also good idea to override methods `foreach` and
    `size` for efficiency.
    
      """ }
    
      "A mutable Set" - {
        "should allow an element to be added" in {
          Given("an empty mutable Set")
          val set = mutable.Set.empty[String]
    
          When("an element is added")
          set += "clarity"
    
          Then("the Set should have size 1")
          assert(set.size === 1)
    
          And("the Set should contain the added element")
          assert(set.contains("clarity"))
    
          markup("This test finished with a **bold** statement!")
        }
      }
    }
    

    Although all of ScalaTest's built-in reporters will display the markup text in some form, the HTML reporter will format the markup information into HTML. Thus, the main purpose of markup is to add nicely formatted text to HTML reports. Here's what the above SetSpec would look like in the HTML reporter:

    Notifiers and alerters

    ScalaTest records text passed to info and markup during tests, and sends the recorded text in the recordedEvents field of test completion events like TestSucceeded and TestFailed. This allows string reporters (like the standard out reporter) to show info and markup text after the test name in a color determined by the outcome of the test. For example, if the test fails, string reporters will show the info and markup text in red. If a test succeeds, string reporters will show the info and markup text in green. While this approach helps the readability of reports, it means that you can't use info to get status updates from long running tests.

    To get immediate (i.e., non-recorded) notifications from tests, you can use note (a Notifier) and alert (an Alerter). Here's an example showing the differences:

    package org.scalatest.examples.freespec.note
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends FreeSpec {
    
      "A mutable Set" - {
        "should allow an element to be added" in {
    
          info("info is recorded")
          markup("markup is *also* recorded")
          note("notes are sent immediately")
          alert("alerts are also sent immediately")
    
          val set = mutable.Set.empty[String]
          set += "clarity"
          assert(set.size === 1)
          assert(set.contains("clarity"))
        }
      }
    }
    

    scala> org.scalatest.run(new SetSpec)
    SetSpec:
     A mutable Set
       + notes are sent immediately
       + alerts are also sent immediately
     - should allow an element to be added
       + info is recorded
       + markup is *also* recorded
    

    Another example is slowpoke notifications. If you find a test is taking a long time to complete, but you're not sure which test, you can enable slowpoke notifications. ScalaTest will use an Alerter to fire an event whenever a test has been running longer than a specified amount of time.

    In summary, use info and markup for text that should form part of the specification output. Use note and alert to send status notifications. (Because the HTML reporter is intended to produce a readable, printable specification, info and markup text will appear in the HTML report, but note and alert text will not.)

    Pending tests

    A pending test is one that has been given a name but is not yet implemented. The purpose of pending tests is to facilitate a style of testing in which documentation of behavior is sketched out before tests are written to verify that behavior (and often, before the behavior of the system being tested is itself implemented). Such sketches form a kind of specification of what tests and functionality to implement later.

    To support this style of testing, a test can be given a name that specifies one bit of behavior required by the system being tested. The test can also include some code that sends more information about the behavior to the reporter when the tests run. At the end of the test, it can call method pending, which will cause it to complete abruptly with TestPendingException.

    Because tests in ScalaTest can be designated as pending with TestPendingException, both the test name and any information sent to the reporter when running the test can appear in the report of a test run. (In other words, the code of a pending test is executed just like any other test.) However, because the test completes abruptly with TestPendingException, the test will be reported as pending, to indicate the actual test, and possibly the functionality it is intended to test, has not yet been implemented. You can mark tests as pending in a FreeSpec like this:

    package org.scalatest.examples.freespec.pending
    
    import org.scalatest._
    
    class SetSpec extends FreeSpec {
    
      "A Set" - {
        "when empty" - {
          "should have size 0" in (pending)
    
          "should produce NoSuchElementException when head is invoked" in {
            assertThrows[NoSuchElementException] {
              Set.empty.head
            }
          }
        }
      }
    }
    

    If you run this version of SetSpec with:

    scala> org.scalatest.run(new SetSpec)
    

    It will run both tests but report that should have size 0 is pending. You'll see:

    A Set
      when empty
      - should have size 0 (pending)
      - should produce NoSuchElementException when head is invoked
    

    One difference between an ignored test and a pending one is that an ignored test is intended to be used during a significant refactorings of the code under test, when tests break and you don't want to spend the time to fix all of them immediately. You can mark some of those broken tests as ignored temporarily, so that you can focus the red bar on just failing tests you actually want to fix immediately. Later you can go back and fix the ignored tests. In other words, by ignoring some failing tests temporarily, you can more easily notice failed tests that you actually want to fix. By contrast, a pending test is intended to be used before a test and/or the code under test is written. Pending indicates you've decided to write a test for a bit of behavior, but either you haven't written the test yet, or have only written part of it, or perhaps you've written the test but don't want to implement the behavior it tests until after you've implemented a different bit of behavior you realized you need first. Thus ignored tests are designed to facilitate refactoring of existing code whereas pending tests are designed to facilitate the creation of new code.

    One other difference between ignored and pending tests is that ignored tests are implemented as a test tag that is excluded by default. Thus an ignored test is never executed. By contrast, a pending test is implemented as a test that throws TestPendingException (which is what calling the pending method does). Thus the body of pending tests are executed up until they throw TestPendingException. The reason for this difference is that it enables your unfinished test to send InfoProvided messages to the reporter before it completes abruptly with TestPendingException, as shown in the previous example on Informers that used the GivenWhenThen trait. For example, the following snippet in a FreeSpec:

     "The Scala language" - {
        "should add correctly" in {
          Given("two integers")
          When("they are added")
          Then("the result is the sum of the two numbers")
          pending
        }
        // ...
    

    Would yield the following output when run in the interpreter:

    The Scala language
    - should add correctly (pending)
      + Given two integers
      + When they are added
      + Then the result is the sum of the two numbers
    

    Tagging tests

    A FreeSpec's tests may be classified into groups by tagging them with string names. As with any suite, when executing a FreeSpec, groups of tests can optionally be included and/or excluded. To tag a FreeSpec's tests, you pass objects that extend class org.scalatest.Tag to methods that register tests. Class Tag takes one parameter, a string name. If you have created tag annotation interfaces as described in the Tag documentation, then you will probably want to use tag names on your test functions that match. To do so, simply pass the fully qualified names of the tag interfaces to the Tag constructor. For example, if you've defined a tag annotation interface with fully qualified name, com.mycompany.tags.DbTest, then you could create a matching tag for FreeSpecs like this:

    import org.scalatest.Tag
    
    object DbTest extends Tag("com.mycompany.tags.DbTest")
    

    Given these definitions, you could tag FreeSpec tests like this:

    package org.scalatest.examples.freespec.tagging
    
    import org.scalatest.Tag
    
    object DbTest extends Tag("com.mycompany.tags.DbTest")
    
    import org.scalatest.FreeSpec
    import org.scalatest.tagobjects.Slow
    
    class SetSpec extends FreeSpec {
    
      "A Set" - {
        "when empty" - {
          "should have size 0" taggedAs(Slow) in {
            assert(Set.empty.size === 0)
          }
    
          "should produce NoSuchElementException when head is invoked" taggedAs(Slow, DbTest) in {
            assertThrows[NoSuchElementException] {
              Set.empty.head
            }
          }
        }
      }
    }
    

    This code marks both tests with the org.scalatest.tags.Slow tag, and the second test with the com.mycompany.tags.DbTest tag.

    The run method takes a Filter, whose constructor takes an optional Set[String] called tagsToInclude and a Set[String] called tagsToExclude. If tagsToInclude is None, all tests will be run except those those belonging to tags listed in the tagsToExclude Set. If tagsToInclude is defined, only tests belonging to tags mentioned in the tagsToInclude set, and not mentioned in tagsToExclude, will be run.

    It is recommended, though not required, that you create a corresponding tag annotation when you create a Tag object. A tag annotation (on the JVM, not Scala.js) allows you to tag all the tests of a FreeSpec in one stroke by annotating the class. For more information and examples, see the documentation for class Tag. On Scala.js, to tag all tests of a suite, you'll need to tag each test individually at the test site.

    Shared fixtures

    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.

    ScalaTest recommends three techniques to eliminate such code duplication:

    • Refactor using Scala
    • Override withFixture
    • Mix in a before-and-after trait

    Each technique is geared towards helping you reduce code duplication without introducing instance vars, shared mutable objects, or other dependencies between tests. Eliminating shared mutable state across tests will make your test code easier to reason about and more amenable for parallel test execution.

    The following sections describe these techniques, including explaining the recommended usage for each. But first, here's a table summarizing the options:

    Refactor using Scala when different tests need different fixtures.
    get-fixture methods The extract method refactor helps you create a fresh instances of mutable fixture objects in each test that needs them, but doesn't help you clean them up when you're done.
    fixture-context objects By placing fixture methods and fields into traits, you can easily give each test just the newly created fixtures it needs by mixing together traits. Use this technique when you need different combinations of mutable fixture objects in different tests, and don't need to clean up after.
    loan-fixture methods Factor out dupicate code with the loan pattern when different tests need different fixtures that must be cleaned up afterwards.
    Override withFixture when most or all tests need the same fixture.
    withFixture(NoArgTest) The recommended default approach when most or all tests need the same fixture treatment. This general technique allows you, for example, to perform side effects at the beginning and end of all or most tests, transform the outcome of tests, retry tests, make decisions based on test names, tags, or other test data. Use this technique unless:
    Different tests need different fixtures (refactor using Scala instead)
    An exception in fixture code should abort the suite, not fail the test (use a before-and-after trait instead)
    You have objects to pass into tests (override withFixture(OneArgTest) instead)
    withFixture(OneArgTest) Use when you want to pass the same fixture object or objects as a parameter into all or most tests.
    Mix in a before-and-after trait when you want an aborted suite, not a failed test, if the fixture code fails.
    BeforeAndAfter Use this boilerplate-buster when you need to perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.
    BeforeAndAfterEach Use when you want to stack traits that perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.

    Calling get-fixture methods

    If you need to create the same mutable fixture objects in multiple tests, and don't need to clean them up after using them, the simplest approach is to write one or more get-fixture methods. A get-fixture method returns a new instance of a needed fixture object (or an holder object containing multiple fixture objects) each time it is called. You can call a get-fixture method at the beginning of each test that needs the fixture, storing the returned object or objects in local variables. Here's an example:

    package org.scalatest.examples.freespec.getfixture
    
    import org.scalatest.FreeSpec
    import collection.mutable.ListBuffer
    
    class ExampleSpec extends FreeSpec {
    
      class Fixture {
        val builder = new StringBuilder("ScalaTest is ")
        val buffer = new ListBuffer[String]
      }
    
      def fixture = new Fixture
    
      "Testing" - {
        "should be easy" in {
          val f = fixture
          f.builder.append("easy!")
          assert(f.builder.toString === "ScalaTest is easy!")
          assert(f.buffer.isEmpty)
          f.buffer += "sweet"
        }
    
        "should be fun" in {
          val f = fixture
          f.builder.append("fun!")
          assert(f.builder.toString === "ScalaTest is fun!")
          assert(f.buffer.isEmpty)
        }
      }
    }
    

    The “f.” in front of each use of a fixture object provides a visual indication of which objects are part of the fixture, but if you prefer, you can import the the members with “import f._” and use the names directly.

    If you need to configure fixture objects differently in different tests, you can pass configuration into the get-fixture method. For example, if you could pass in an initial value for a mutable fixture object as a parameter to the get-fixture method.

    Instantiating fixture-context objects

    An alternate technique that is especially useful when different tests need different combinations of fixture objects is to define the fixture objects as instance variables of fixture-context objects whose instantiation forms the body of tests. Like get-fixture methods, fixture-context objects are only appropriate if you don't need to clean up the fixtures after using them.

    To use this technique, you define instance variables intialized with fixture objects in traits and/or classes, then in each test instantiate an object that contains just the fixture objects needed by the test. Traits allow you to mix together just the fixture objects needed by each test, whereas classes allow you to pass data in via a constructor to configure the fixture objects. Here's an example in which fixture objects are partitioned into two traits and each test just mixes together the traits it needs:

    package org.scalatest.examples.freespec.fixturecontext
    
    import collection.mutable.ListBuffer
    import org.scalatest.FreeSpec
    
    class ExampleSpec extends FreeSpec {
    
      trait Builder {
        val builder = new StringBuilder("ScalaTest is ")
      }
    
      trait Buffer {
        val buffer = ListBuffer("ScalaTest", "is")
      }
    
      "Testing" - {
        // This test needs the StringBuilder fixture
        "should be productive" in new Builder {
          builder.append("productive!")
          assert(builder.toString === "ScalaTest is productive!")
        }
      }
    
      "Test code" - {
        // This test needs the ListBuffer[String] fixture
        "should be readable" in new Buffer {
          buffer += ("readable!")
          assert(buffer === List("ScalaTest", "is", "readable!"))
        }
    
        // This test needs both the StringBuilder and ListBuffer
        "should be clear and concise" in new Builder with Buffer {
          builder.append("clear!")
          buffer += ("concise!")
          assert(builder.toString === "ScalaTest is clear!")
          assert(buffer === List("ScalaTest", "is", "concise!"))
        }
      }
    }
    

    Overriding withFixture(NoArgTest)

    Although the get-fixture method and fixture-context object approaches take care of setting up a fixture at the beginning of each test, they don't address the problem of cleaning up a fixture at the end of the test. If you just need to perform a side-effect at the beginning or end of a test, and don't need to actually pass any fixture objects into the test, you can override withFixture(NoArgTest), one of ScalaTest's lifecycle methods defined in trait Suite.

    Trait Suite's implementation of runTest passes a no-arg test function to withFixture(NoArgTest). It is withFixture's responsibility to invoke that test function. Suite's implementation of withFixture simply invokes the function, like this:

    // Default implementation in trait Suite
    protected def withFixture(test: NoArgTest) = {
      test()
    }
    

    You can, therefore, override withFixture to perform setup before and/or cleanup after invoking the test function. If you have cleanup to perform, you should invoke the test function inside a try block and perform the cleanup in a finally clause, in case an exception propagates back through withFixture. (If a test fails because of an exception, the test function invoked by withFixture will result in a Failed wrapping the exception. Nevertheless, best practice is to perform cleanup in a finally clause just in case an exception occurs.)

    The withFixture method is designed to be stacked, and to enable this, you should always call the super implementation of withFixture, 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)”, like this:

    // Your implementation
    override def withFixture(test: NoArgTest) = {
      // Perform setup
      try super.withFixture(test) // Invoke the test function
      finally {
        // Perform cleanup
      }
    }
    

    Here's an example in which withFixture(NoArgTest) is used to take a snapshot of the working directory if a test fails, and send that information to the reporter:

    package org.scalatest.examples.freespec.noargtest
    
    import java.io.File
    import org.scalatest._
    
    class ExampleSpec extends FreeSpec {
    
      override def withFixture(test: NoArgTest) = {
    
        super.withFixture(test) match {
          case failed: Failed =>
            val currDir = new File(".")
            val fileNames = currDir.list()
            info("Dir snapshot: " + fileNames.mkString(", "))
            failed
          case other => other
        }
      }
    
      "This test" - {
        "should succeed" in {
          assert(1 + 1 === 2)
        }
    
        "should fail" in {
          assert(1 + 1 === 3)
        }
      }
    }
    

    Running this version of ExampleSuite in the interpreter in a directory with two files, hello.txt and world.txt would give the following output:

    scala> org.scalatest.run(new ExampleSuite)
    ExampleSuite:
    This test
    - should succeed
    - should fail *** FAILED ***
      2 did not equal 3 (:33)
      + Dir snapshot: hello.txt, world.txt 
    

    Note that the NoArgTest passed to withFixture, in addition to an apply method that executes the test, also includes the test name and the config map passed to runTest. Thus you can also use the test name and configuration objects in your withFixture implementation.

    Calling loan-fixture methods

    If you need to both pass a fixture object into a test and perform cleanup at the end of the test, you'll need to use the loan pattern. If different tests need different fixtures that require cleanup, you can implement the loan pattern directly by writing loan-fixture methods. A loan-fixture method takes a function whose body forms part or all of a test's code. It creates a fixture, passes it to the test code by invoking the function, then cleans up the fixture after the function returns.

    The following example shows three tests that use two fixtures, a database and a file. Both require cleanup after, so each is provided via a loan-fixture method. (In this example, the database is simulated with a StringBuffer.)

    package org.scalatest.examples.freespec.loanfixture
    
    import java.util.concurrent.ConcurrentHashMap
    
    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)
      }
    }
    
    import org.scalatest.FreeSpec
    import DbServer._
    import java.util.UUID.randomUUID
    import java.io._
    
    class ExampleSpec extends FreeSpec {
    
      def withDatabase(testCode: Db => Any) {
        val dbName = randomUUID.toString
        val db = createDb(dbName) // create the fixture
        try {
          db.append("ScalaTest is ") // perform setup
          testCode(db) // "loan" the fixture to the test
        }
        finally removeDb(dbName) // clean up the fixture
      }
    
      def withFile(testCode: (File, FileWriter) => Any) {
        val file = File.createTempFile("hello", "world") // create the fixture
        val writer = new FileWriter(file)
        try {
          writer.write("ScalaTest is ") // set up the fixture
          testCode(file, writer) // "loan" the fixture to the test
        }
        finally writer.close() // clean up the fixture
      }
    
      "Testing" - {
        // This test needs the file fixture
        "should be productive" in withFile { (file, writer) =>
          writer.write("productive!")
          writer.flush()
          assert(file.length === 24)
        }
      }
    
      "Test code" - {
        // This test needs the database fixture
        "should be readable" in withDatabase { db =>
          db.append("readable!")
          assert(db.toString === "ScalaTest is readable!")
        }
    
        // This test needs both the file and the database
        "should be clear and concise" in withDatabase { db =>
          withFile { (file, writer) => // loan-fixture methods compose
            db.append("clear!")
            writer.write("concise!")
            writer.flush()
            assert(db.toString === "ScalaTest is clear!")
            assert(file.length === 21)
          }
        }
      }
    }
    

    As demonstrated by the last test, loan-fixture methods compose. Not only do loan-fixture methods allow you to give each test the fixture it needs, they allow you to give a test multiple fixtures and clean everything up afterwards.

    Also demonstrated in this example is 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 this example. This keeps tests completely isolated, allowing you to run them in parallel if desired.

    Overriding withFixture(OneArgTest)

    If all or most tests need the same fixture, you can avoid some of the boilerplate of the loan-fixture method approach by using a fixture.FreeSpec and overriding withFixture(OneArgTest). Each test in a fixture.FreeSpec takes a fixture as a parameter, allowing you to pass the fixture into the test. You must indicate the type of the fixture parameter by specifying FixtureParam, and implement a withFixture method that takes a OneArgTest. This withFixture method is responsible for invoking the one-arg test function, so you can perform fixture set up before, and clean up after, invoking and passing the fixture into the test function.

    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)
        }
      }
    }
    

    In this example, the tests actually required two fixture objects, a File and a FileWriter. In such situations you can simply define the FixtureParam type to be a tuple containing the objects, or as is done in this example, a case class containing the objects. For more information on the withFixture(OneArgTest) technique, see the documentation for fixture.FreeSpec.

    Mixing in BeforeAndAfter

    In all the shared fixture examples shown so far, the activities of creating, setting up, and cleaning up the fixture objects have been performed during the test. This means that if an exception occurs during any of these activities, it will be reported as a test failure. Sometimes, however, you may want setup to happen before the test starts, and cleanup after the test has completed, so that if an exception occurs during setup or cleanup, the entire suite aborts and no more tests are attempted. The simplest way to accomplish this in ScalaTest is to mix in trait BeforeAndAfter. With this trait you can denote a bit of code to run before each test with before and/or after each test each test with after, like this:

    package org.scalatest.examples.freespec.beforeandafter
    
    import org.scalatest.FreeSpec
    import org.scalatest.BeforeAndAfter
    import collection.mutable.ListBuffer
    
    class ExampleSpec extends FreeSpec with BeforeAndAfter {
    
      val builder = new StringBuilder
      val buffer = new ListBuffer[String]
    
      before {
        builder.append("ScalaTest is ")
      }
    
      after {
        builder.clear()
        buffer.clear()
      }
    
      "Testing" - {
        "should be easy" in {
          builder.append("easy!")
          assert(builder.toString === "ScalaTest is easy!")
          assert(buffer.isEmpty)
          buffer += "sweet"
        }
    
        "should be fun" in {
          builder.append("fun!")
          assert(builder.toString === "ScalaTest is fun!")
          assert(buffer.isEmpty)
        }
      }
    }
    

    Note that the only way before and after code can communicate with test code is via some side-effecting mechanism, commonly by reassigning instance vars or by changing the state of mutable objects held from instance vals (as in this example). If using instance vars or mutable objects held from instance vals you wouldn't be able to run tests in parallel in the same instance of the test class (on the JVM, not Scala.js) unless you synchronized access to the shared, mutable state. This is why ScalaTest's ParallelTestExecution trait extends OneInstancePerTest. By running each test in its own instance of the class, each test has its own copy of the instance variables, so you don't need to synchronize. If you mixed ParallelTestExecution into the ExampleSuite above, the tests would run in parallel just fine without any synchronization needed on the mutable StringBuilder and ListBuffer[String] objects.

    Although BeforeAndAfter provides a minimal-boilerplate way to execute code before and after tests, it isn't designed to enable stackable traits, because the order of execution would be non-obvious. If you want to factor out before and after code that is common to multiple test suites, you should use trait BeforeAndAfterEach instead, as shown later in the next section, composing fixtures by stacking traits.

    Composing fixtures by stacking traits

    In larger projects, teams often end up with several different fixtures that test classes need in different combinations, and possibly initialized (and cleaned up) in different orders. A good way to accomplish this in ScalaTest is to factor the individual fixtures into traits that can be composed using the stackable trait pattern. This can be done, for example, by placing withFixture methods in several traits, each of which call super.withFixture. Here's an example in which the StringBuilder and ListBuffer[String] fixtures used in the previous examples have been factored out into two stackable fixture traits named Builder and Buffer:

    package org.scalatest.examples.freespec.composingwithfixture
    
    import org.scalatest._
    import collection.mutable.ListBuffer
    
    trait Builder extends TestSuiteMixin { this: TestSuite =>
    
      val builder = new StringBuilder
    
      abstract override def withFixture(test: NoArgTest) = {
        builder.append("ScalaTest is ")
        try super.withFixture(test) // To be stackable, must call super.withFixture
        finally builder.clear()
      }
    }
    
    trait Buffer extends TestSuiteMixin { this: TestSuite =>
    
      val buffer = new ListBuffer[String]
    
      abstract override def withFixture(test: NoArgTest) = {
        try super.withFixture(test) // To be stackable, must call super.withFixture
        finally buffer.clear()
      }
    }
    
    class ExampleSpec extends FreeSpec with Builder with Buffer {
    
      "Testing" - {
        "should be easy" in {
          builder.append("easy!")
          assert(builder.toString === "ScalaTest is easy!")
          assert(buffer.isEmpty)
          buffer += "sweet"
        }
    
        "should be fun" in {
          builder.append("fun!")
          assert(builder.toString === "ScalaTest is fun!")
          assert(buffer.isEmpty)
          buffer += "clear"
        }
      }
    }
    

    By mixing in both the Builder and Buffer traits, ExampleSuite gets both fixtures, which will be initialized before each test and cleaned up after. The order the traits are mixed together determines the order of execution. In this case, Builder is “super” to Buffer. If you wanted Buffer to be “super” to Builder, you need only switch the order you mix them together, like this:

    class Example2Spec extends FreeSpec with Buffer with Builder
    

    And if you only need one fixture you mix in only that trait:

    class Example3Spec extends FreeSpec with Builder
    

    Another way to create stackable fixture traits is by extending the BeforeAndAfterEach and/or BeforeAndAfterAll traits. BeforeAndAfterEach has 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). Similarly, BeforeAndAfterAll has a beforeAll method that will be run before all tests, and an afterAll method that will be run after all tests. Here's what the previously shown example would look like if it were rewritten to use the BeforeAndAfterEach methods instead of withFixture:

    package org.scalatest.examples.freespec.composingbeforeandaftereach
    
    import org.scalatest._
    import org.scalatest.BeforeAndAfterEach
    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 FreeSpec with Builder with Buffer {
    
      "Testing" - {
        "should be easy" in {
          builder.append("easy!")
          assert(builder.toString === "ScalaTest is easy!")
          assert(buffer.isEmpty)
          buffer += "sweet"
        }
    
        "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 difference between stacking traits that extend BeforeAndAfterEach versus traits that implement withFixture is that setup and cleanup code happens before and after the test in BeforeAndAfterEach, but at the beginning and end of the test in withFixture. Thus if a withFixture method completes abruptly with an exception, it is considered a failed test. By contrast, if any of the beforeEach or afterEach methods of BeforeAndAfterEach complete abruptly, it is considered an aborted suite, which will result in a SuiteAborted event.

    Shared tests

    Sometimes you may want to run the same test code on different fixture objects. In other words, you may want to write tests that are "shared" by different fixture objects. To accomplish this in a FreeSpec, you first place shared tests in behavior functions. These behavior functions will be invoked during the construction phase of any FreeSpec that uses them, so that the tests they contain will be registered as tests in that FreeSpec. For example, given this stack class:

    import scala.collection.mutable.ListBuffer
    
    class Stack[T] {
    
      val MAX = 10
      private val buf = new ListBuffer[T]
    
      def push(o: T) {
        if (!full)
          buf.prepend(o)
        else
          throw new IllegalStateException("can't push onto a full stack")
      }
    
      def pop(): T = {
        if (!empty)
          buf.remove(0)
        else
          throw new IllegalStateException("can't pop an empty stack")
      }
    
      def peek: T = {
        if (!empty)
          buf(0)
        else
          throw new IllegalStateException("can't pop an empty stack")
      }
    
      def full: Boolean = buf.size == MAX
      def empty: Boolean = buf.size == 0
      def size = buf.size
    
      override def toString = buf.mkString("Stack(", ", ", ")")
    }
    

    You may want to test the Stack class in different states: empty, full, with one item, with one item less than capacity, etc. You may find you have several tests that make sense any time the stack is non-empty. Thus you'd ideally want to run those same tests for three stack fixture objects: a full stack, a stack with a one item, and a stack with one item less than capacity. With shared tests, you can factor these tests out into a behavior function, into which you pass the stack fixture to use when running the tests. So in your FreeSpec for stack, you'd invoke the behavior function three times, passing in each of the three stack fixtures so that the shared tests are run for all three fixtures. You can define a behavior function that encapsulates these shared tests inside the FreeSpec that uses them. If they are shared between different FreeSpecs, however, you could also define them in a separate trait that is mixed into each FreeSpec that uses them.

    For example, here the nonEmptyStack behavior function (in this case, a behavior method) is defined in a trait along with another method containing shared tests for non-full stacks:

    trait StackBehaviors { this: FreeSpec =>
    
      def nonEmptyStack(newStack: => Stack[Int], lastItemAdded: Int) {
    
        "be non-empty" in {
          assert(!newStack.empty)
        }
    
        "return the top item on peek" in {
          assert(newStack.peek === lastItemAdded)
        }
    
        "not remove the top item on peek" in {
          val stack = newStack
          val size = stack.size
          assert(stack.peek === lastItemAdded)
          assert(stack.size === size)
        }
    
        "remove the top item on pop" in {
          val stack = newStack
          val size = stack.size
          assert(stack.pop === lastItemAdded)
          assert(stack.size === size - 1)
        }
      }
    
      def nonFullStack(newStack: => Stack[Int]) {
    
        "not be full" in {
          assert(!newStack.full)
        }
    
        "add to the top on push" in {
          val stack = newStack
          val size = stack.size
          stack.push(7)
          assert(stack.size === size + 1)
          assert(stack.peek === 7)
        }
      }
    }
    

    Given these behavior functions, you could invoke them directly, but FreeSpec offers a DSL for the purpose, which looks like this:

    behave like nonEmptyStack(stackWithOneItem, lastValuePushed)
    behave like nonFullStack(stackWithOneItem)
    

    If you prefer to use an imperative style to change fixtures, for example by mixing in BeforeAndAfterEach and reassigning a stack var in beforeEach, you could write your behavior functions in the context of that var, which means you wouldn't need to pass in the stack fixture because it would be in scope already inside the behavior function. In that case, your code would look like this:

    behave like nonEmptyStack // assuming lastValuePushed is also in scope inside nonEmptyStack
    behave like nonFullStack
    

    The recommended style, however, is the functional, pass-all-the-needed-values-in style. Here's an example:

    class SharedTestExampleSpec extends FreeSpec with StackBehaviors {
    
      // Stack fixture creation methods
      def emptyStack = new Stack[Int]
    
      def fullStack = {
        val stack = new Stack[Int]
        for (i <- 0 until stack.MAX)
          stack.push(i)
        stack
      }
    
      def stackWithOneItem = {
        val stack = new Stack[Int]
        stack.push(9)
        stack
      }
    
      def stackWithOneItemLessThanCapacity = {
        val stack = new Stack[Int]
        for (i <- 1 to 9)
          stack.push(i)
        stack
      }
    
      val lastValuePushed = 9
    
      "A Stack" - {
        "when empty" - {
          "should be empty" in {
            assert(emptyStack.empty)
          }
    
          "should complain on peek" in {
            assertThrows[IllegalStateException] {
              emptyStack.peek
            }
          }
    
          "should complain on pop" in {
            assertThrows[IllegalStateException] {
              emptyStack.pop
            }
          }
        }
    
        "when it contains one item" - {
          "should" - {
            behave like nonEmptyStack(stackWithOneItem, lastValuePushed)
            behave like nonFullStack(stackWithOneItem)
          }
        }
    
        "when it contains one item less than capacity" - {
          "should" - {
            behave like nonEmptyStack(stackWithOneItemLessThanCapacity, lastValuePushed)
            behave like nonFullStack(stackWithOneItemLessThanCapacity)
          }
        }
    
        "when full" - {
          "should be full" in {
            assert(fullStack.full)
          }
    
          "should" - {
            behave like nonEmptyStack(fullStack, lastValuePushed)
          }
    
          "should complain on a push" in {
            assertThrows[IllegalStateException] {
              fullStack.push(10)
            }
          }
        }
      }
    }
    

    If you load these classes into the Scala interpreter (with scalatest's JAR file on the class path), and execute it, you'll see:

    scala> org.scalatest.run(new SharedTestExampleSpec)
    SharedTestExampleSpec:
    A Stack
      when empty
      - should be empty
      - should complain on peek
      - should complain on pop
      when it contains one item
        should
        - be non-empty
        - return the top item on peek
        - not remove the top item on peek
        - remove the top item on pop
        - not be full
        - add to the top on push
      when it contains one item less than capacity
        should
        - be non-empty
        - return the top item on peek
        - not remove the top item on peek
        - remove the top item on pop
        - not be full
        - add to the top on push
      when full
      - should be full
        should
        - be non-empty
        - return the top item on peek
        - not remove the top item on peek
        - remove the top item on pop
      - should complain on a push
    

    One thing to keep in mind when using shared tests is that in ScalaTest, each test in a suite must have a unique name. If you register the same tests repeatedly in the same suite, one problem you may encounter is an exception at runtime complaining that multiple tests are being registered with the same test name. A good way to solve this problem in a FreeSpec is to make sure each test is in the context of different surrounding description clauses, because a test's name is the concatenation of its surrounding clauses, followed by the test's text. For example, the following code in a FreeSpec would register a test with the name "A Stack when empty should be empty":

    "A Stack" - {
      "when empty" - {
        "should be empty" in {
          assert(emptyStack.empty)
        }
      }
    }
    // ...
    

    If the "should be empty" test was factored out into a behavior function, it could be called repeatedly so long as each invocation of the behavior function is in the context of a different surrounding description (dash) clauses.

    Annotations
    @Finders()
  54. trait FreeSpecLike extends TestSuite with TestRegistration with Informing with Notifying with Alerting with Documenting

    Permalink

    Implementation trait for class FreeSpec, which facilitates a “behavior-driven” style of development (BDD), in which tests are nested inside text clauses denoted with the dash operator (-).

    Implementation trait for class FreeSpec, which facilitates a “behavior-driven” style of development (BDD), in which tests are nested inside text clauses denoted with the dash operator (-).

    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 FreeSpec into some other class, you can use this trait instead, because class 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 FreeSpec.

    Annotations
    @Finders() @JSExportDescendentClasses( true )
  55. class FunSpec extends FunSpecLike

    Permalink

    Facilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.

    Facilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.

    Recommended Usage: For teams coming from Ruby's RSpec tool, FunSpec will feel familiar and comfortable; More generally, for any team that prefers BDD, FunSpec's nesting and gentle guide to structuring text (with describe and it) provide an excellent general-purpose choice for writing specification-style tests.

    Here's an example FunSpec:

    package org.scalatest.examples.funspec
    
    import org.scalatest.FunSpec
    
    class SetSpec extends FunSpec {
    
      describe("A Set") {
        describe("when empty") {
          it("should have size 0") {
            assert(Set.empty.size === 0)
          }
    
          it("should produce NoSuchElementException when head is invoked") {
            assertThrows[NoSuchElementException] {
              Set.empty.head
            }
          }
        }
      }
    }
    

    A FunSpec contains describe clauses and tests. You define a describe clause with describe, and a test with either it or they. describe, it, and they are methods, defined in FunSpec, which will be invoked by the primary constructor of SetSpec. A describe clause names, or gives more information about, the subject (class or other entity) you are specifying and testing. In the previous example, "A Set" is the subject under specification and test. With each test you provide a string (the spec text) that specifies one bit of behavior of the subject, and a block of code that tests that behavior. You place the spec text between the parentheses, followed by the test code between curly braces. The test code will be wrapped up as a function passed as a by-name parameter to it (or they), which will register the test for later execution.

    Note: the they method is intended for use when the subject is plural, for example:

    describe("The combinators") {
      they("should be easy to learn") {}
      they("should be efficient") {}
      they("should do something cool") {}
    }
    

    A FunSpec's lifecycle has two phases: the registration phase and the ready phase. It starts in registration phase and enters ready phase the first time run is called on it. It then remains in ready phase for the remainder of its lifetime.

    Tests can only be registered with the it or they methods while the FunSpec is in its registration phase. Any attempt to register a test after the FunSpec has entered its ready phase, i.e., after run has been invoked on the FunSpec, will be met with a thrown TestRegistrationClosedException. The recommended style of using FunSpec is to register tests during object construction as is done in all the examples shown here. If you keep to the recommended style, you should never see a TestRegistrationClosedException.

    When you execute a FunSpec, it will send Formatters in the events it sends to the Reporter. ScalaTest's built-in reporters will report these events in such a way that the output is easy to read as an informal specification of the subject being tested. For example, were you to run SetSpec from within the Scala interpreter:

    scala> org.scalatest.run(new SetSpec)
    

    You would see:

    A Set
      when empty
      - should have size 0
      - should produce NoSuchElementException when head is invoked
    

    Or, to run just the “A Set when empty should have size 0” test, you could pass that test's name, or any unique substring of the name, such as "size 0" or even just "0". Here's an example:

    scala> org.scalatest.run(new SetSuite, "size 0")
    A Set
      when empty
      - should have size 0
    

    You can also pass to execute a config map of key-value pairs, which will be passed down into suites and tests, as well as other parameters that configure the run itself. For more information on running in the Scala interpreter, see the documentation for execute (below) and the ScalaTest shell.

    The execute method invokes a run method that takes two parameters. This run method, which actually executes the suite, will usually be invoked by a test runner, such as run, tools.Runner, a build tool, or an IDE.

    Note: FunSpec's syntax is in great part inspired by RSpec, a Ruby BDD framework.

    Ignored tests

    To support the common use case of temporarily disabling a test, with the good intention of resurrecting the test at a later time, FunSpec provides registration methods that start with ignore instead of it or they. For example, to temporarily disable the test with the text "should have size 0", just change “it” into “ignore,” like this:

    package org.scalatest.examples.funspec.ignore
    
    import org.scalatest.FunSpec
    
    class SetSpec extends FunSpec {
    
      describe("A Set") {
        describe("when empty") {
          ignore("should have size 0") {
            assert(Set.empty.size === 0)
          }
    
          it("should produce NoSuchElementException when head is invoked") {
            assertThrows[NoSuchElementException] {
              Set.empty.head
            }
          }
        }
      }
    }
    

    If you run this version of SetSpec with:

    scala> org.scalatest.run(new SetSpec)
    

    It will run only the second test and report that the first test was ignored:

    A Set
      when empty
      - should have size 0 !!! IGNORED !!!
      - should produce NoSuchElementException when head is invoked
    

    If you wish to temporarily ignore an entire suite of tests, you can (on the JVM, not Scala.js) annotate the test class with @Ignore, like this:

    package org.scalatest.examples.funspec.ignoreall
    
    import org.scalatest.FunSpec
    import org.scalatest.Ignore
    
    @Ignore
    class SetSpec extends FunSpec {
    
      describe("A Set") {
        describe("when empty") {
          it("should have size 0") {
            assert(Set.empty.size === 0)
          }
    
          it("should produce NoSuchElementException when head is invoked") {
            assertThrows[NoSuchElementException] {
              Set.empty.head
            }
          }
        }
      }
    }
    

    When you mark a test class with a tag annotation, ScalaTest will mark each test defined in that class with that tag. Thus, marking the SetSpec in the above example with the @Ignore tag annotation means that both tests in the class will be ignored. If you run the above SetSpec in the Scala interpreter, you'll see:

    scala> org.scalatest.run(new SetSpec)
    SetSpec:
    A Set
      when empty
      - should have size 0 !!! IGNORED !!!
      - should produce NoSuchElementException when head is invoked !!! IGNORED !!!
    

    Note that marking a test class as ignored won't prevent it from being discovered by ScalaTest. Ignored classes will be discovered and run, and all their tests will be reported as ignored. This is intended to keep the ignored class visible, to encourage the developers to eventually fix and “un-ignore” it. If you want to prevent a class from being discovered at all (on the JVM, not Scala.js), use the DoNotDiscover annotation instead.

    Informers

    One of the parameters to FunSpec's run method is a Reporter, which will collect and report information about the running suite of tests. Information about suites and tests that were run, whether tests succeeded or failed, and tests that were ignored will be passed to the Reporter as the suite runs. Most often the reporting done by default by FunSpec's methods will be sufficient, but occasionally you may wish to provide custom information to the Reporter from a test. For this purpose, an Informer that will forward information to the current Reporter is provided via the info parameterless method. You can pass the extra information to the Informer via one of its apply methods. The Informer will then pass the information to the Reporter via an InfoProvided event. Here's an example in which the Informer returned by info is used implicitly by the Given, When, and Then methods of trait GivenWhenThen:

    package org.scalatest.examples.funspec.info
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends FunSpec with GivenWhenThen {
    
      describe("A mutable Set") {
        it("should allow an element to be added") {
          Given("an empty mutable Set")
          val set = mutable.Set.empty[String]
    
          When("an element is added")
          set += "clarity"
    
          Then("the Set should have size 1")
          assert(set.size === 1)
    
          And("the Set should contain the added element")
          assert(set.contains("clarity"))
    
          info("That's all folks!")
        }
      }
    }
    

    If you run this FunSpec from the interpreter, you will see the following output:

    scala> org.scalatest.run(new SetSpec)
    A mutable Set
    - should allow an element to be added
      + Given an empty mutable Set
      + When an element is added
      + Then the Set should have size 1
      + And the Set should contain the added element
      + That's all folks! 
    

    Documenters

    FunSpec also provides a markup method that returns a Documenter, which allows you to send to the Reporter text formatted in Markdown syntax. You can pass the extra information to the Documenter via its apply method. The Documenter will then pass the information to the Reporter via an MarkupProvided event.

    Here's an example FunSpec that uses markup:

    package org.scalatest.examples.funspec.markup
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends FunSpec with GivenWhenThen {
    
      markup { """
    
    Mutable Set
    -----------
    
    A set is a collection that contains no duplicate elements.
    
    To implement a concrete mutable set, you need to provide implementations
    of the following methods:
    
        def contains(elem: A): Boolean
        def iterator: Iterator[A]
        def += (elem: A): this.type
        def -= (elem: A): this.type
    
    If you wish that methods like `take`,
    `drop`, `filter` return the same kind of set,
    you should also override:
    
        def empty: This
    
    It is also good idea to override methods `foreach` and
    `size` for efficiency.
    
      """ }
    
      describe("A mutable Set") {
        it("should allow an element to be added") {
          Given("an empty mutable Set")
          val set = mutable.Set.empty[String]
    
          When("an element is added")
          set += "clarity"
    
          Then("the Set should have size 1")
          assert(set.size === 1)
    
          And("the Set should contain the added element")
          assert(set.contains("clarity"))
    
          markup("This test finished with a **bold** statement!")
        }
      }
    }
    

    Although all of ScalaTest's built-in reporters will display the markup text in some form, the HTML reporter will format the markup information into HTML. Thus, the main purpose of markup is to add nicely formatted text to HTML reports. Here's what the above SetSpec would look like in the HTML reporter:

    Notifiers and alerters

    ScalaTest records text passed to info and markup during tests, and sends the recorded text in the recordedEvents field of test completion events like TestSucceeded and TestFailed. This allows string reporters (like the standard out reporter) to show info and markup text after the test name in a color determined by the outcome of the test. For example, if the test fails, string reporters will show the info and markup text in red. If a test succeeds, string reporters will show the info and markup text in green. While this approach helps the readability of reports, it means that you can't use info to get status updates from long running tests.

    To get immediate (i.e., non-recorded) notifications from tests, you can use note (a Notifier) and alert (an Alerter). Here's an example showing the differences:

    package org.scalatest.examples.funspec.note
    
    import collection.mutable
    import org.scalatest._
    
    class SetSpec extends FunSpec {
    
      describe("A mutable Set") {
        it("should allow an element to be added") {
    
          info("info is recorded")
          markup("markup is *also* recorded")
          note("notes are sent immediately")
          alert("alerts are also sent immediately")
    
          val set = mutable.Set.empty[String]
          set += "clarity"
          assert(set.size === 1)
          assert(set.contains("clarity"))
        }
      }
    }
    

    Because note and alert information is sent immediately, it will appear before the test name in string reporters, and its color will be unrelated to the ultimate outcome of the test: note text will always appear in green, alert text will always appear in yellow. Here's an example:

    scala> org.scalatest.run(new SetSpec)
    SetSpec:
    A mutable Set
      + notes are sent immediately
      + alerts are also sent immediately
    - should allow an element to be added
      + info is recorded
      + markup is *also* recorded
    

    Another example is slowpoke notifications. If you find a test is taking a long time to complete, but you're not sure which test, you can enable slowpoke notifications. ScalaTest will use an Alerter to fire an event whenever a test has been running longer than a specified amount of time.

    In summary, use info and markup for text that should form part of the specification output. Use note and alert to send status notifications. (Because the HTML reporter is intended to produce a readable, printable specification, info and markup text will appear in the HTML report, but note and alert text will not.)

    Pending tests

    A pending test is one that has been given a name but is not yet implemented. The purpose of pending tests is to facilitate a style of testing in which documentation of behavior is sketched out before tests are written to verify that behavior (and often, before the behavior of the system being tested is itself implemented). Such sketches form a kind of specification of what tests and functionality to implement later.

    To support this style of testing, a test can be given a name that specifies one bit of behavior required by the system being tested. The test can also include some code that sends more information about the behavior to the reporter when the tests run. At the end of the test, it can call method pending, which will cause it to complete abruptly with TestPendingException.

    Because tests in ScalaTest can be designated as pending with TestPendingException, both the test name and any information sent to the reporter when running the test can appear in the report of a test run. (In other words, the code of a pending test is executed just like any other test.) However, because the test completes abruptly with TestPendingException, the test will be reported as pending, to indicate the actual test, and possibly the functionality, has not yet been implemented.

    You can mark a test as pending in FunSpec by placing "(pending)" after the test name, like this:

    package org.scalatest.examples.funspec.pending
    
    import org.scalatest._
    
    class SetSpec extends FunSpec {
    
      describe("A Set") {
        describe("when empty") {
          it("should have size 0") (pending)
    
          it("should produce NoSuchElementException when head is invoked") {
            assertThrows[NoSuchElementException] {
              Set.empty.head
            }
          }
        }
      }
    }
    

    (Note: "(pending)" is the body of the test. Thus the test contains just one statement, an invocation of the pending method, which throws TestPendingException.) If you run this version of SetSpec with:

    scala> org.scalatest.run(new SetSpec)
    

    It will run both tests, but report that the test named "should have size 0" is pending. You'll see:

    A Set
      when empty
      - should have size 0 (pending)
      - should produce NoSuchElementException when head is invoked
    

    Tagging tests

    A FunSpec's tests may be classified into groups by tagging them with string names. As with any suite, when executing a FunSpec, groups of tests can optionally be included and/or excluded. To tag a FunSpec's tests, you pass objects that extend class org.scalatest.Tag to methods that register tests. Class Tag takes one parameter, a string name. If you have created tag annotation interfaces as described in the Tag documentation, then you will probably want to use tag names on your test functions that match. To do so, simply pass the fully qualified names of the tag interfaces to the Tag constructor. For example, if you've defined a tag annotation interface with fully qualified name, com.mycompany.tags.DbTest, then you could create a matching tag for FunSpecs like this:

    package org.scalatest.examples.funspec.tagging
    
    import org.scalatest.Tag
    
    object DbTest extends Tag("com.mycompany.tags.DbTest")
    

    Given these definitions, you could place FunSpec tests into groups with tags like this:

    import org.scalatest.FunSpec
    import org.scalatest.tagobjects.Slow
    
    class SetSpec extends FunSpec {
    
      describe("A Set") {
        describe("when empty") {
          it("should have size 0", Slow) {
            assert(Set.empty.size === 0)
          }
    
          it("should produce NoSuchElementException when head is invoked", Slow, DbTest) {
            assertThrows[NoSuchElementException] {
              Set.empty.head
            }
          }
        }
      }
    }
    

    This code marks both tests with the org.scalatest.tags.Slow tag, and the second test with the com.mycompany.tags.DbTest tag.

    The run method takes a Filter, whose constructor takes an optional Set[String] called tagsToInclude and a Set[String] called tagsToExclude. If tagsToInclude is None, all tests will be run except those those belonging to tags listed in the tagsToExclude Set. If tagsToInclude is defined, only tests belonging to tags mentioned in the tagsToInclude set, and not mentioned in tagsToExclude, will be run.

    It is recommended, though not required, that you create a corresponding tag annotation when you create a Tag object. A tag annotation (on the JVM, not Scala.js) allows you to tag all the tests of a FunSpec in one stroke by annotating the class. For more information and examples, see the documentation for class Tag. On Scala.js, to tag all tests of a suite, you'll need to tag each test individually at the test site.

    Shared fixtures

    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.

    ScalaTest recommends three techniques to eliminate such code duplication:

    • Refactor using Scala
    • Override withFixture
    • Mix in a before-and-after trait

    Each technique is geared towards helping you reduce code duplication without introducing instance vars, shared mutable objects, or other dependencies between tests. Eliminating shared mutable state across tests will make your test code easier to reason about and more amenable for parallel test execution.

    The following sections describe these techniques, including explaining the recommended usage for each. But first, here's a table summarizing the options:

    Refactor using Scala when different tests need different fixtures.
    get-fixture methods The extract method refactor helps you create a fresh instances of mutable fixture objects in each test that needs them, but doesn't help you clean them up when you're done.
    fixture-context objects By placing fixture methods and fields into traits, you can easily give each test just the newly created fixtures it needs by mixing together traits. Use this technique when you need different combinations of mutable fixture objects in different tests, and don't need to clean up after.
    loan-fixture methods Factor out dupicate code with the loan pattern when different tests need different fixtures that must be cleaned up afterwards.
    Override withFixture when most or all tests need the same fixture.
    withFixture(NoArgTest) The recommended default approach when most or all tests need the same fixture treatment. This general technique allows you, for example, to perform side effects at the beginning and end of all or most tests, transform the outcome of tests, retry tests, make decisions based on test names, tags, or other test data. Use this technique unless:
    Different tests need different fixtures (refactor using Scala instead)
    An exception in fixture code should abort the suite, not fail the test (use a before-and-after trait instead)
    You have objects to pass into tests (override withFixture(OneArgTest) instead)
    withFixture(OneArgTest) Use when you want to pass the same fixture object or objects as a parameter into all or most tests.
    Mix in a before-and-after trait when you want an aborted suite, not a failed test, if the fixture code fails.
    BeforeAndAfter Use this boilerplate-buster when you need to perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.
    BeforeAndAfterEach Use when you want to stack traits that perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.

    Calling get-fixture methods

    If you need to create the same mutable fixture objects in multiple tests, and don't need to clean them up after using them, the simplest approach is to write one or more get-fixture methods. A get-fixture method returns a new instance of a needed fixture object (or an holder object containing multiple fixture objects) each time it is called. You can call a get-fixture method at the beginning of each test that needs the fixture, storing the returned object or objects in local variables. Here's an example:

    package org.scalatest.examples.funspec.getfixture
    
    import org.scalatest.FunSpec
    import collection.mutable.ListBuffer
    
    class ExampleSpec extends FunSpec {
    
      class Fixture {
        val builder = new StringBuilder("ScalaTest is ")
        val buffer = new ListBuffer[String]
      }
    
      def fixture = new Fixture
    
      describe("Testing") {
        it("should be easy") {
          val f = fixture
          f.builder.append("easy!")
          assert(f.builder.toString === "ScalaTest is easy!")
          assert(f.buffer.isEmpty)
          f.buffer += "sweet"
        }
    
        it("should be fun") {
          val f = fixture
          f.builder.append("fun!")
          assert(f.builder.toString === "ScalaTest is fun!")
          assert(f.buffer.isEmpty)
        }
      }
    }
    

    The “f.” in front of each use of a fixture object provides a visual indication of which objects are part of the fixture, but if you prefer, you can import the the members with “import f._” and use the names directly.

    If you need to configure fixture objects differently in different tests, you can pass configuration into the get-fixture method. For example, if you could pass in an initial value for a mutable fixture object as a parameter to the get-fixture method.

    Instantiating fixture-context objects

    An alternate technique that is especially useful when different tests need different combinations of fixture objects is to define the fixture objects as instance variables of fixture-context objects whose instantiation forms the body of tests. Like get-fixture methods, fixture-context objects are only appropriate if you don't need to clean up the fixtures after using them.

    To use this technique, you define instance variables intialized with fixture objects in traits and/or classes, then in each test instantiate an object that contains just the fixture objects needed by the test. Traits allow you to mix together just the fixture objects needed by each test, whereas classes allow you to pass data in via a constructor to configure the fixture objects. Here's an example in which fixture objects are partitioned into two traits and each test just mixes together the traits it needs:

    package org.scalatest.examples.funspec.fixturecontext
    
    import collection.mutable.ListBuffer
    import org.scalatest.FunSpec
    
    class ExampleSpec extends FunSpec {
    
      trait Builder {
        val builder = new StringBuilder("ScalaTest is ")
      }
    
      trait Buffer {
        val buffer = ListBuffer("ScalaTest", "is")
      }
    
      describe("Testing") {
        // This test needs the StringBuilder fixture
        it("should be productive") {
          new Builder {
            builder.append("productive!")
            assert(builder.toString === "ScalaTest is productive!")
          }
        }
      }
    
      describe("Test code") {
        // This test needs the ListBuffer[String] fixture
        it("should be readable") {
          new Buffer {
            buffer += ("readable!")
            assert(buffer === List("ScalaTest", "is", "readable!"))
          }
        }
    
        // This test needs both the StringBuilder and ListBuffer
        it("should be clear and concise") {
          new Builder with Buffer {
            builder.append("clear!")
            buffer += ("concise!")
            assert(builder.toString === "ScalaTest is clear!")
            assert(buffer === List("ScalaTest", "is", "concise!"))
          }
        }
      }
    }
    

    Overriding withFixture(NoArgTest)

    Although the get-fixture method and fixture-context object approaches take care of setting up a fixture at the beginning of each test, they don't address the problem of cleaning up a fixture at the end of the test. If you just need to perform a side-effect at the beginning or end of a test, and don't need to actually pass any fixture objects into the test, you can override withFixture(NoArgTest), one of ScalaTest's lifecycle methods defined in trait Suite.

    Trait Suite's implementation of runTest passes a no-arg test function to withFixture(NoArgTest). It is withFixture's responsibility to invoke that test function. Suite's implementation of withFixture simply invokes the function, like this:

    // Default implementation in trait Suite
    protected def withFixture(test: NoArgTest) = {
      test()
    }
    

    You can, therefore, override withFixture to perform setup before and/or cleanup after invoking the test function. If you have cleanup to perform, you should invoke the test function inside a try block and perform the cleanup in a finally clause, in case an exception propagates back through withFixture. (If a test fails because of an exception, the test function invoked by withFixture will result in a Failed wrapping the exception. Nevertheless, best practice is to perform cleanup in a finally clause just in case an exception occurs.)

    The withFixture method is designed to be stacked, and to enable this, you should always call the super implementation of withFixture, 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)”, like this:

    // Your implementation
    override def withFixture(test: NoArgTest) = {
      // Perform setup
      try super.withFixture(test) // Invoke the test function
      finally {
        // Perform cleanup
      }
    }
    

    Here's an example in which withFixture(NoArgTest) is used to take a snapshot of the working directory if a test fails, and send that information to the reporter:

    package org.scalatest.examples.funspec.noargtest
    
    import java.io.File
    import org.scalatest._
    
    class ExampleSpec extends FunSpec {
    
      override def withFixture(test: NoArgTest) = {
    
        try super.withFixture(test) match {
          case failed: Failed =>
            val currDir = new File(".")
            val fileNames = currDir.list()
            info("Dir snapshot: " + fileNames.mkString(", "))
            failed
          case other => other
        }
      }
    
      describe("This test") {
        it("should succeed") {
          assert(1 + 1 === 2)
        }
    
        it("should fail") {
          assert(1 + 1 === 3)
        }
      }
    }
    

    Running this version of ExampleSuite in the interpreter in a directory with two files, hello.txt and world.txt would give the following output:

    scala> org.scalatest.run(new ExampleSuite)
    ExampleSuite:
    This test
    - should succeed
    - should fail *** FAILED ***
      2 did not equal 3 (:33)
      + Dir snapshot: hello.txt, world.txt 
    

    Note that the NoArgTest passed to withFixture, in addition to an apply method that executes the test, also includes the test name and the config map passed to runTest. Thus you can also use the test name and configuration objects in your withFixture implementation.

    Calling loan-fixture methods

    If you need to both pass a fixture object into a test and perform cleanup at the end of the test, you'll need to use the loan pattern. If different tests need different fixtures that require cleanup, you can implement the loan pattern directly by writing loan-fixture methods. A loan-fixture method takes a function whose body forms part or all of a test's code. It creates a fixture, passes it to the test code by invoking the function, then cleans up the fixture after the function returns.

    The following example shows three tests that use two fixtures, a database and a file. Both require cleanup after, so each is provided via a loan-fixture method. (In this example, the database is simulated with a StringBuffer.)

    package org.scalatest.examples.funspec.loanfixture
    
    import java.util.concurrent.ConcurrentHashMap
    
    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)
      }
    }
    
    import org.scalatest.FunSpec
    import DbServer._
    import java.util.UUID.randomUUID
    import java.io._
    
    class ExampleSpec extends FunSpec {
    
      def withDatabase(testCode: Db => Any) {
        val dbName = randomUUID.toString
        val db = createDb(dbName) // create the fixture
        try {
          db.append("ScalaTest is ") // perform setup
          testCode(db) // "loan" the fixture to the test
        }
        finally removeDb(dbName) // clean up the fixture
      }
    
      def withFile(testCode: (File, FileWriter) => Any) {
        val file = File.createTempFile("hello", "world") // create the fixture
        val writer = new FileWriter(file)
        try {
          writer.write("ScalaTest is ") // set up the fixture
          testCode(file, writer) // "loan" the fixture to the test
        }
        finally writer.close() // clean up the fixture
      }
    
      describe("Testing") {
        // This test needs the file fixture
        it("should be productive") {
          withFile { (file, writer) =>
            writer.write("productive!")
            writer.flush()
            assert(file.length === 24)
          }
        }
      }
    
      describe("Test code") {
        // This test needs the database fixture
        it("should be readable") {
          withDatabase { db =>
            db.append("readable!")
            assert(db.toString === "ScalaTest is readable!")
          }
        }
    
        // This test needs both the file and the database
        it("should be clear and concise") {
          withDatabase { db =>
           withFile { (file, writer) => // loan-fixture methods compose
              db.append("clear!")
              writer.write("concise!")
              writer.flush()
              assert(db.toString === "ScalaTest is clear!")
              assert(file.length === 21)
            }
          }
        }
      }
    }
    

    As demonstrated by the last test, loan-fixture methods compose. Not only do loan-fixture methods allow you to give each test the fixture it needs, they allow you to give a test multiple fixtures and clean everything up afterwards.

    Also demonstrated in this example is 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 this example. This keeps tests completely isolated, allowing you to run them in parallel if desired.

    Overriding withFixture(OneArgTest)

    If all or most tests need the same fixture, you can avoid some of the boilerplate of the loan-fixture method approach by using a fixture.Suite and overriding withFixture(OneArgTest). Each test in a fixture.Suite takes a fixture as a parameter, allowing you to pass the fixture into the test. You must indicate the type of the fixture parameter by specifying FixtureParam, and implement a withFixture method that takes a OneArgTest. This withFixture method is responsible for invoking the one-arg test function, so you can perform fixture set up before, and clean up after, invoking and passing the fixture into the test function.

    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)
        }
      }
    }
    

    In this example, the tests actually required two fixture objects, a File and a FileWriter. In such situations you can simply define the FixtureParam type to be a tuple containing the objects, or as is done in this example, a case class containing the objects. For more information on the withFixture(OneArgTest) technique, see the documentation for fixture.FunSpec.

    Mixing in BeforeAndAfter

    In all the shared fixture examples shown so far, the activities of creating, setting up, and cleaning up the fixture objects have been performed during the test. This means that if an exception occurs during any of these activities, it will be reported as a test failure. Sometimes, however, you may want setup to happen before the test starts, and cleanup after the test has completed, so that if an exception occurs during setup or cleanup, the entire suite aborts and no more tests are attempted. The simplest way to accomplish this in ScalaTest is to mix in trait BeforeAndAfter. With this trait you can denote a bit of code to run before each test with before and/or after each test each test with after, like this:

    package org.scalatest.examples.funspec.beforeandafter
    
    import org.scalatest.FunSpec
    import org.scalatest.BeforeAndAfter
    import collection.mutable.ListBuffer
    
    class ExampleSpec extends FunSpec with BeforeAndAfter {
    
      val builder = new StringBuilder
      val buffer = new ListBuffer[String]
    
      before {
        builder.append("ScalaTest is ")
      }
    
      after {
        builder.clear()
        buffer.clear()
      }
    
      describe("Testing") {
        it("should be easy") {
          builder.append("easy!")
          assert(builder.toString === "ScalaTest is easy!")
          assert(buffer.isEmpty)
          buffer += "sweet"
        }
    
        it("should be fun") {
          builder.append("fun!")
          assert(builder.toString === "ScalaTest is fun!")
          assert(buffer.isEmpty)
        }
      }
    }
    

    Note that the only way before and after code can communicate with test code is via some side-effecting mechanism, commonly by reassigning instance vars or by changing the state of mutable objects held from instance vals (as in this example). If using instance vars or mutable objects held from instance vals you wouldn't be able to run tests in parallel in the same instance of the test class (on the JVM, not Scala.js) unless you synchronized access to the shared, mutable state. This is why ScalaTest's ParallelTestExecution trait extends OneInstancePerTest. By running each test in its own instance of the class, each test has its own copy of the instance variables, so you don't need to synchronize. If you mixed ParallelTestExecution into the ExampleSuite above, the tests would run in parallel just fine without any synchronization needed on the mutable StringBuilder and ListBuffer[String] objects.

    Although BeforeAndAfter provides a minimal-boilerplate way to execute code before and after tests, it isn't designed to enable stackable traits, because the order of execution would be non-obvious. If you want to factor out before and after code that is common to multiple test suites, you should use trait BeforeAndAfterEach instead, as shown later in the next section, composing fixtures by stacking traits.

    Composing fixtures by stacking traits

    In larger projects, teams often end up with several different fixtures that test classes need in different combinations, and possibly initialized (and cleaned up) in different orders. A good way to accomplish this in ScalaTest is to factor the individual fixtures into traits that can be composed using the stackable trait pattern. This can be done, for example, by placing withFixture methods in several traits, each of which call super.withFixture. Here's an example in which the StringBuilder and ListBuffer[String] fixtures used in the previous examples have been factored out into two stackable fixture traits named Builder and Buffer:

    package org.scalatest.examples.funspec.composingwithfixture
    
    import org.scalatest._
    import collection.mutable.ListBuffer
    
    trait Builder extends TestSuiteMixin { this: TestSuite =>
    
      val builder = new StringBuilder
    
      abstract override def withFixture(test: NoArgTest) = {
        builder.append("ScalaTest is ")
        try super.withFixture(test) // To be stackable, must call super.withFixture
        finally builder.clear()
      }
    }
    
    trait Buffer extends TestSuiteMixin { this: TestSuite =>
    
      val buffer = new ListBuffer[String]
    
      abstract override def withFixture(test: NoArgTest) = {
        try super.withFixture(test) // To be stackable, must call super.withFixture
        finally buffer.clear()
      }
    }
    
    class ExampleSpec extends FunSpec with Builder with Buffer {
    
      describe("Testing") {
        it("should be easy") {
          builder.append("easy!")
          assert(builder.toString === "ScalaTest is easy!")
          assert(buffer.isEmpty)
          buffer += "sweet"
        }
    
        it("should be fun") {
          builder.append("fun!")
          assert(builder.toString === "ScalaTest is fun!")
          assert(buffer.isEmpty)
          buffer += "clear"
        }
      }
    }
    

    By mixing in both the Builder and Buffer traits, ExampleSuite gets both fixtures, which will be initialized before each test and cleaned up after. The order the traits are mixed together determines the order of execution. In this case, Builder is “super” to Buffer. If you wanted Buffer to be “super” to Builder, you need only switch the order you mix them together, like this:

    class Example2Spec extends FunSpec with Buffer with Builder
    

    And if you only need one fixture you mix in only that trait:

    class Example3Spec extends FunSpec with Builder
    

    Another way to create stackable fixture traits is by extending the BeforeAndAfterEach and/or BeforeAndAfterAll traits. BeforeAndAfterEach has 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). Similarly, BeforeAndAfterAll has a beforeAll method that will be run before all tests, and an afterAll method that will be run after all tests. Here's what the previously shown example would look like if it were rewritten to use the BeforeAndAfterEach methods instead of withFixture:

    package org.scalatest.examples.funspec.composingbeforeandaftereach
    
    import org.scalatest._
    import org.scalatest.BeforeAndAfterEach
    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 FunSpec with Builder with Buffer {
    
      describe("Testing") {
        it("should be easy") {
          builder.append("easy!")
          assert(builder.toString === "ScalaTest is easy!")
          assert(buffer.isEmpty)
          buffer += "sweet"
        }
    
        it("should be fun") {
          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 difference between stacking traits that extend BeforeAndAfterEach versus traits that implement withFixture is that setup and cleanup code happens before and after the test in BeforeAndAfterEach, but at the beginning and end of the test in withFixture. Thus if a withFixture method completes abruptly with an exception, it is considered a failed test. By contrast, if any of the beforeEach or afterEach methods of BeforeAndAfterEach complete abruptly, it is considered an aborted suite, which will result in a SuiteAborted event.

    Shared tests

    Sometimes you may want to run the same test code on different fixture objects. In other words, you may want to write tests that are "shared" by different fixture objects. To accomplish this in a FunSpec, you first place shared tests in behavior functions. These behavior functions will be invoked during the construction phase of any FunSpec that uses them, so that the tests they contain will be registered as tests in that FunSpec. For example, given this stack class:

    import scala.collection.mutable.ListBuffer
    
    class Stack[T] {
    
      val MAX = 10
      private val buf = new ListBuffer[T]
    
      def push(o: T) {
        if (!full)
          buf.prepend(o)
        else
          throw new IllegalStateException("can't push onto a full stack")
      }
    
      def pop(): T = {
        if (!empty)
          buf.remove(0)
        else
          throw new IllegalStateException("can't pop an empty stack")
      }
    
      def peek: T = {
        if (!empty)
          buf(0)
        else
          throw new IllegalStateException("can't pop an empty stack")
      }
    
      def full: Boolean = buf.size == MAX
      def empty: Boolean = buf.size == 0
      def size = buf.size
    
      override def toString = buf.mkString("Stack(", ", ", ")")
    }
    

    You may want to test the Stack class in different states: empty, full, with one item, with one item less than capacity, etc. You may find you have several tests that make sense any time the stack is non-empty. Thus you'd ideally want to run those same tests for three stack fixture objects: a full stack, a stack with a one item, and a stack with one item less than capacity. With shared tests, you can factor these tests out into a behavior function, into which you pass the stack fixture to use when running the tests. So in your FunSpec for stack, you'd invoke the behavior function three times, passing in each of the three stack fixtures so that the shared tests are run for all three fixtures. You can define a behavior function that encapsulates these shared tests inside the FunSpec that uses them. If they are shared between different FunSpecs, however, you could also define them in a separate trait that is mixed into each FunSpec that uses them.

    For example, here the nonEmptyStack behavior function (in this case, a behavior method) is defined in a trait along with another method containing shared tests for non-full stacks:

    trait StackBehaviors { this: FunSpec =>
    
      def nonEmptyStack(newStack: => Stack[Int], lastItemAdded: Int) {
    
        it("should be non-empty") {
          assert(!newStack.empty)
        }
    
        it("should return the top item on peek") {
          assert(newStack.peek === lastItemAdded)
        }
    
        it("should not remove the top item on peek") {
          val stack = newStack
          val size = stack.size
          assert(stack.peek === lastItemAdded)
          assert(stack.size === size)
        }
    
        it("should remove the top item on pop") {
          val stack = newStack
          val size = stack.size
          assert(stack.pop === lastItemAdded)
          assert(stack.size === size - 1)
        }
      }
    
      def nonFullStack(newStack: => Stack[Int]) {
    
        it("should not be full") {
          assert(!newStack.full)
        }
    
        it("should add to the top on push") {
          val stack = newStack
          val size = stack.size
          stack.push(7)
          assert(stack.size === size + 1)
          assert(stack.peek === 7)
        }
      }
    }
    

    Given these behavior functions, you could invoke them directly, but FunSpec offers a DSL for the purpose, which looks like this:

    it should behave like nonEmptyStack(stackWithOneItem, lastValuePushed)
    it should behave like nonFullStack(stackWithOneItem)
    

    If you prefer to use an imperative style to change fixtures, for example by mixing in BeforeAndAfterEach and reassigning a stack var in beforeEach, you could write your behavior functions in the context of that var, which means you wouldn't need to pass in the stack fixture because it would be in scope already inside the behavior function. In that case, your code would look like this:

    it should behave like nonEmptyStack // assuming lastValuePushed is also in scope inside nonEmptyStack
    it should behave like nonFullStack
    

    The recommended style, however, is the functional, pass-all-the-needed-values-in style. Here's an example:

    class SharedTestExampleSpec extends FunSpec with StackBehaviors {
    
      // Stack fixture creation methods
      def emptyStack = new Stack[Int]
    
      def fullStack = {
        val stack = new Stack[Int]
        for (i <- 0 until stack.MAX)
          stack.push(i)
        stack
      }
    
      def stackWithOneItem = {
        val stack = new Stack[Int]
        stack.push(9)
        stack
      }
    
      def stackWithOneItemLessThanCapacity = {
        val stack = new Stack[Int]
        for (i <- 1 to 9)
          stack.push(i)
        stack
      }
    
      val lastValuePushed = 9
    
      describe("A Stack") {
    
        describe("(when empty)") {
    
          it("should be empty") {
            assert(emptyStack.empty)
          }
    
          it("should complain on peek") {
            assertThrows[IllegalStateException] {
              emptyStack.peek
            }
          }
    
          it("should complain on pop") {
            assertThrows[IllegalStateException] {
              emptyStack.pop
            }
          }
        }
    
        describe("(with one item)") {
          it should behave like nonEmptyStack(stackWithOneItem, lastValuePushed)
          it should behave like nonFullStack(stackWithOneItem)
        }
    
        describe("(with one item less than capacity)") {
          it should behave like nonEmptyStack(stackWithOneItemLessThanCapacity, lastValuePushed)
          it should behave like nonFullStack(stackWithOneItemLessThanCapacity)
        }
    
        describe("(full)") {
    
          it("should be full") {
            assert(fullStack.full)
          }
    
          it should behave like nonEmptyStack(fullStack, lastValuePushed)
    
          it("should complain on a push") {
            assertThrows[IllegalStateException] {
              fullStack.push(10)
            }
          }
        }
      }
    }
    

    If you load these classes into the Scala interpreter (with scalatest's JAR file on the class path), and execute it, you'll see:

    scala> org.scalatest.run(new StackSpec)
    A Stack (when empty)
    - should be empty
    - should complain on peek
    - should complain on pop
    A Stack (with one item)
    - should be non-empty
    - should return the top item on peek
    - should not remove the top item on peek
    - should remove the top item on pop
    - should not be full
    - should add to the top on push
    A Stack (with one item less than capacity)
    - should be non-empty
    - should return the top item on peek
    - should not remove the top item on peek
    - should remove the top item on pop
    - should not be full
    - should add to the top on push
    A Stack (full)
    - should be full
    - should be non-empty
    - should return the top item on peek
    - should not remove the top item on peek
    - should remove the top item on pop
    - should complain on a push
    

    One thing to keep in mind when using shared tests is that in ScalaTest, each test in a suite must have a unique name. If you register the same tests repeatedly in the same suite, one problem you may encounter is an exception at runtime complaining that multiple tests are being registered with the same test name. A good way to solve this problem in a FunSpec is to surround each invocation of a behavior function with a describe clause, which will prepend a string to each test name. For example, the following code in a FunSpec would register a test with the name "A Stack (when empty) should be empty":

      describe("A Stack") {
    
        describe("(when empty)") {
    
          it("should be empty") {
            assert(emptyStack.empty)
          }
          // ...
    

    If the "should be empty" test was factored out into a behavior function, it could be called repeatedly so long as each invocation of the behavior function is inside a different set of describe clauses.

    Annotations
    @Finders()
  56. trait FunSpecLike extends TestSuite with TestRegistration with Informing with Notifying with Alerting with Documenting

    Permalink

    Implementation trait for class FunSpec, which facilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.

    Implementation trait for class FunSpec, which facilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.

    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 FunSpec into some other class, you can use this trait instead, because class 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 FunSpec.

    Annotations
    @Finders() @JSExportDescendentClasses( true )
  57. class FunSuite extends FunSuiteLike

    Permalink

    A suite of tests in which each test is represented as a function value.

    A suite of tests in which each test is represented as a function value. The “Fun” in FunSuite stands for “function.”

    Recommended Usage: For teams coming from xUnit, FunSuite feels comfortable and familiar while still giving some benefits of BDD: FunSuite makes it easy to write descriptive test names, natural to write focused tests, and generates specification-like output that can facilitate communication among stakeholders.

    Here's an example FunSuite:

    package org.scalatest.examples.funsuite
    
    import org.scalatest.FunSuite
    
    class SetSuite extends FunSuite {
    
      test("An empty Set should have size 0") {
        assert(Set.empty.size === 0)
      }
    
      test("Invoking head on an empty Set should produce NoSuchElementException") {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
    

    test” is a method, defined in FunSuite, which will be invoked by the primary constructor of SetSuite. You specify the name of the test as a string between the parentheses, and the test code itself between curly braces. The test code is a function passed as a by-name parameter to test, which registers it for later execution.

    A FunSuite's lifecycle has two phases: the registration phase and the ready phase. It starts in registration phase and enters ready phase the first time run is called on it. It then remains in ready phase for the remainder of its lifetime.

    Tests can only be registered with the test method while the FunSuite is in its registration phase. Any attempt to register a test after the FunSuite has entered its ready phase, i.e., after run has been invoked on the FunSuite, will be met with a thrown TestRegistrationClosedException. The recommended style of using FunSuite is to register tests during object construction as is done in all the examples shown here. If you keep to the recommended style, you should never see a TestRegistrationClosedException.

    Note: FunSuite was in part inspired by Rehersal, an early test framework for Scala.

    Ignored tests

    To support the common use case of temporarily disabling a test, with the good intention of resurrecting the test at a later time, FunSuite provides registration methods that start with ignore instead of test. Here's an example:

    package org.scalatest.examples.funsuite.ignore
    
    import org.scalatest.FunSuite
    
    class SetSuite extends FunSuite {
    
      ignore("An empty Set should have size 0") {
        assert(Set.empty.size === 0)
      }
    
      test("Invoking head on an empty Set should produce NoSuchElementException") {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
    

    If you run this version of SetSuite with:

    scala> org.scalatest.run(new SetSuite)
    

    It will run only the second test and report that the first test was ignored:

    SetSuite:
    - An empty Set should have size 0 !!! IGNORED !!!
    - Invoking head on an empty Set should produce NoSuchElementException
    

    If you wish to temporarily ignore an entire suite of tests, you can (on the JVM, not Scala.js) annotate the test class with @Ignore, like this:

    package org.scalatest.examples.funsuite.ignoreall
    
    import org.scalatest.FunSuite
    import org.scalatest.Ignore
    
    @Ignore
    class SetSuite extends FunSuite {
    
      test("An empty Set should have size 0") {
        assert(Set.empty.size === 0)
      }
    
      test("Invoking head on an empty Set should produce NoSuchElementException") {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
    

    When you mark a test class with a tag annotation, ScalaTest will mark each test defined in that class with that tag. Thus, marking the SetSuite in the above example with the @Ignore tag annotation means that both tests in the class will be ignored. If you run the above SetSuite in the Scala interpreter, you'll see:

    scala> org.scalatest.run(new SetSuite)
    SetSuite:
    - An empty Set should have size 0 !!! IGNORED !!!
    - Invoking head on an empty Set should produce NoSuchElementException !!! IGNORED !!!
    

    Note that marking a test class as ignored won't prevent it from being discovered by ScalaTest. Ignored classes will be discovered and run, and all their tests will be reported as ignored. This is intended to keep the ignored class visible, to encourage the developers to eventually fix and “un-ignore” it. If you want to prevent a class from being discovered at all (on the JVM, not Scala.js), use the DoNotDiscover annotation instead.

    Informers

    One of the parameters to FunSuite's run method is a Reporter, which will collect and report information about the running suite of tests. Information about suites and tests that were run, whether tests succeeded or failed, and tests that were ignored will be passed to the Reporter as the suite runs. Most often the reporting done by default by FunSuite's methods will be sufficient, but occasionally you may wish to provide custom information to the Reporter from a test. For this purpose, an Informer that will forward information to the current Reporter is provided via the info parameterless method. You can pass the extra information to the Informer via its apply method. The Informer will then pass the information to the Reporter via an InfoProvided event. Here's an example that shows both a direct use as well as an indirect use through the methods of GivenWhenThen:

    package org.scalatest.examples.funsuite.info
    
    import collection.mutable
    import org.scalatest._
    
    class SetSuite extends FunSuite with GivenWhenThen {
    
      test("An element can be added to an empty mutable Set") {
    
        Given("an empty mutable Set")
        val set = mutable.Set.empty[String]
    
        When("an element is added")
        set += "clarity"
    
        Then("the Set should have size 1")
        assert(set.size === 1)
    
        And("the Set should contain the added element")
        assert(set.contains("clarity"))
    
        info("That's all folks!")
      }
    }
    

    If you run this FunSuite from the interpreter, you will see the following output:

    scala> org.scalatest.run(new SetSuite)
    SetSuite:
    - an element can be added to an empty mutable Set
      + Given an empty mutable Set
      + When an element is added
      + Then the Set should have size 1
      + And the Set should contain the added element
      + That's all folks!
    

    Documenters

    FunSuite also provides a markup method that returns a Documenter, which allows you to send to the Reporter text formatted in Markdown syntax. You can pass the extra information to the Documenter via its apply method. The Documenter will then pass the information to the Reporter via an MarkupProvided event.

    Here's an example FunSuite that uses markup:

    package org.scalatest.examples.funsuite.markup
    
    import collection.mutable
    import org.scalatest._
    
    class SetSuite extends FunSuite with GivenWhenThen {
    
      markup { """
    
    Mutable Set
    -----------
    
    A set is a collection that contains no duplicate elements.
    
    To implement a concrete mutable set, you need to provide implementations
    of the following methods:
    
        def contains(elem: A): Boolean
        def iterator: Iterator[A]
        def += (elem: A): this.type
        def -= (elem: A): this.type
    
    If you wish that methods like `take`,
    `drop`, `filter` return the same kind of set,
    you should also override:
    
        def empty: This
    
    It is also good idea to override methods `foreach` and
    `size` for efficiency.
    
      """ }
    
      test("An element can be added to an empty mutable Set") {
    
        Given("an empty mutable Set")
        val set = mutable.Set.empty[String]
    
        When("an element is added")
        set += "clarity"
    
        Then("the Set should have size 1")
        assert(set.size === 1)
    
        And("the Set should contain the added element")
        assert(set.contains("clarity"))
    
        markup("This test finished with a **bold** statement!")
      }
    }
    

    Although all of ScalaTest's built-in reporters will display the markup text in some form, the HTML reporter will format the markup information into HTML. Thus, the main purpose of markup is to add nicely formatted text to HTML reports. Here's what the above SetSpec would look like in the HTML reporter:

    Notifiers and alerters

    ScalaTest records text passed to info and markup during tests, and sends the recorded text in the recordedEvents field of test completion events like TestSucceeded and TestFailed. This allows string reporters (like the standard out reporter) to show info and markup text after the test name in a color determined by the outcome of the test. For example, if the test fails, string reporters will show the info and markup text in red. If a test succeeds, string reporters will show the info and markup text in green. While this approach helps the readability of reports, it means that you can't use info to get status updates from long running tests.

    To get immediate (i.e., non-recorded) notifications from tests, you can use note (a Notifier) and alert (an Alerter). Here's an example showing the differences:

    package org.scalatest.examples.funsuite.note
    
    import collection.mutable
    import org.scalatest._
    
    class SetSuite extends FunSuite {
    
      test("An element can be added to an empty mutable Set") {
    
        info("info is recorded")
        markup("markup is *also* recorded")
        note("notes are sent immediately")
        alert("alerts are also sent immediately")
    
        val set = mutable.Set.empty[String]
        set += "clarity"
        assert(set.size === 1)
        assert(set.contains("clarity"))
      }
    }
    

    Because note and alert information is sent immediately, it will appear before the test name in string reporters, and its color will be unrelated to the ultimate outcome of the test: note text will always appear in green, alert text will always appear in yellow. Here's an example:

    scala> org.scalatest.run(new SetSpec)
    SetSuite:
      + notes are sent immediately
      + alerts are also sent immediately
    - An element can be added to an empty mutable Set
      + info is recorded
      + markup is *also* recorded
    

    Another example is slowpoke notifications. If you find a test is taking a long time to complete, but you're not sure which test, you can enable slowpoke notifications. ScalaTest will use an Alerter to fire an event whenever a test has been running longer than a specified amount of time.

    In summary, use info and markup for text that should form part of the specification output. Use note and alert to send status notifications. (Because the HTML reporter is intended to produce a readable, printable specification, info and markup text will appear in the HTML report, but note and alert text will not.)

    Pending tests

    A pending test is one that has been given a name but is not yet implemented. The purpose of pending tests is to facilitate a style of testing in which documentation of behavior is sketched out before tests are written to verify that behavior (and often, before the behavior of the system being tested is itself implemented). Such sketches form a kind of specification of what tests and functionality to implement later.

    To support this style of testing, a test can be given a name that specifies one bit of behavior required by the system being tested. The test can also include some code that sends more information about the behavior to the reporter when the tests run. At the end of the test, it can call method pending, which will cause it to complete abruptly with TestPendingException.

    Because tests in ScalaTest can be designated as pending with TestPendingException, both the test name and any information sent to the reporter when running the test can appear in the report of a test run. (In other words, the code of a pending test is executed just like any other test.) However, because the test completes abruptly with TestPendingException, the test will be reported as pending, to indicate the actual test, and possibly the functionality, has not yet been implemented.

    Although pending tests may be used more often in specification-style suites, such as org.scalatest.FunSpec, you can also use it in FunSuite, like this:

    package org.scalatest.examples.funsuite.pending
    
    import org.scalatest._
    
    class SetSuite extends FunSuite {
    
      test("An empty Set should have size 0") (pending)
    
      test("Invoking head on an empty Set should produce NoSuchElementException") {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
    

    (Note: "(pending)" is the body of the test. Thus the test contains just one statement, an invocation of the pending method, which throws TestPendingException.) If you run this version of SetSuite with:

    scala> org.scalatest.run(new SetSuite)
    

    It will run both tests, but report that first test is pending. You'll see:

    SetSuite:
    - An empty Set should have size 0 (pending)
    - Invoking head on an empty Set should produce NoSuchElementException
    

    One difference between an ignored test and a pending one is that an ignored test is intended to be used during a significant refactorings of the code under test, when tests break and you don't want to spend the time to fix all of them immediately. You can mark some of those broken tests as ignored temporarily, so that you can focus the red bar on just failing tests you actually want to fix immediately. Later you can go back and fix the ignored tests. In other words, by ignoring some failing tests temporarily, you can more easily notice failed tests that you actually want to fix. By contrast, a pending test is intended to be used before a test and/or the code under test is written. Pending indicates you've decided to write a test for a bit of behavior, but either you haven't written the test yet, or have only written part of it, or perhaps you've written the test but don't want to implement the behavior it tests until after you've implemented a different bit of behavior you realized you need first. Thus ignored tests are designed to facilitate refactoring of existing code whereas pending tests are designed to facilitate the creation of new code.

    One other difference between ignored and pending tests is that ignored tests are implemented as a test tag that is excluded by default. Thus an ignored test is never executed. By contrast, a pending test is implemented as a test that throws TestPendingException (which is what calling the pending method does). Thus the body of pending tests are executed up until they throw TestPendingException. The reason for this difference is that it enables your unfinished test to send InfoProvided messages to the reporter before it completes abruptly with TestPendingException, as shown in the previous example on Informers that used the GivenWhenThen trait.

    Tagging tests

    A FunSuite's tests may be classified into groups by tagging them with string names. As with any suite, when executing a FunSuite, groups of tests can optionally be included and/or excluded. To tag a FunSuite's tests, you pass objects that extend class org.scalatest.Tag to methods that register tests. Class Tag takes one parameter, a string name. If you have created tag annotation interfaces as described in the Tag documentation, then you will probably want to use tag names on your test functions that match. To do so, simply pass the fully qualified names of the tag interfaces to the Tag constructor. For example, if you've defined a tag annotation interface with fully qualified name, com.mycompany.tags.DbTest, then you could create a matching tag for FunSuites like this:

    package org.scalatest.examples.funsuite.tagging
    
    import org.scalatest.Tag
    
    object DbTest extends Tag("com.mycompany.tags.DbTest")
    

    Given these definitions, you could place FunSuite tests into groups with tags like this:

    import org.scalatest.FunSuite
    import org.scalatest.tagobjects.Slow
    
    class SetSuite extends FunSuite {
    
      test("An empty Set should have size 0", Slow) {
        assert(Set.empty.size === 0)
      }
    
      test("Invoking head on an empty Set should produce NoSuchElementException",
           Slow, DbTest) {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
    

    This code marks both tests with the org.scalatest.tags.Slow tag, and the second test with the com.mycompany.tags.DbTest tag.

    The run method takes a Filter, whose constructor takes an optional Set[String] called tagsToInclude and a Set[String] called tagsToExclude. If tagsToInclude is None, all tests will be run except those those belonging to tags listed in the tagsToExclude Set. If tagsToInclude is defined, only tests belonging to tags mentioned in the tagsToInclude set, and not mentioned in tagsToExclude, will be run.

    It is recommended, though not required, that you create a corresponding tag annotation when you create a Tag object. A tag annotation (on the JVM, not Scala.js) allows you to tag all the tests of a FunSuite in one stroke by annotating the class. For more information and examples, see the documentation for class Tag. On Scala.js, to tag all tests of a suite, you'll need to tag each test individually at the test site.

    Shared fixtures

    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.

    ScalaTest recommends three techniques to eliminate such code duplication:

    • Refactor using Scala
    • Override withFixture
    • Mix in a before-and-after trait

    Each technique is geared towards helping you reduce code duplication without introducing instance vars, shared mutable objects, or other dependencies between tests. Eliminating shared mutable state across tests will make your test code easier to reason about and more amenable for parallel test execution.

    The following sections describe these techniques, including explaining the recommended usage for each. But first, here's a table summarizing the options:

    Refactor using Scala when different tests need different fixtures.
    get-fixture methods The extract method refactor helps you create a fresh instances of mutable fixture objects in each test that needs them, but doesn't help you clean them up when you're done.
    fixture-context objects By placing fixture methods and fields into traits, you can easily give each test just the newly created fixtures it needs by mixing together traits. Use this technique when you need different combinations of mutable fixture objects in different tests, and don't need to clean up after.
    loan-fixture methods Factor out dupicate code with the loan pattern when different tests need different fixtures that must be cleaned up afterwards.
    Override withFixture when most or all tests need the same fixture.
    withFixture(NoArgTest) The recommended default approach when most or all tests need the same fixture treatment. This general technique allows you, for example, to perform side effects at the beginning and end of all or most tests, transform the outcome of tests, retry tests, make decisions based on test names, tags, or other test data. Use this technique unless:
    Different tests need different fixtures (refactor using Scala instead)
    An exception in fixture code should abort the suite, not fail the test (use a before-and-after trait instead)
    You have objects to pass into tests (override withFixture(OneArgTest) instead)
    withFixture(OneArgTest) Use when you want to pass the same fixture object or objects as a parameter into all or most tests.
    Mix in a before-and-after trait when you want an aborted suite, not a failed test, if the fixture code fails.
    BeforeAndAfter Use this boilerplate-buster when you need to perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.
    BeforeAndAfterEach Use when you want to stack traits that perform the same side-effects before and/or after tests, rather than at the beginning or end of tests.

    Calling get-fixture methods

    If you need to create the same mutable fixture objects in multiple tests, and don't need to clean them up after using them, the simplest approach is to write one or more get-fixture methods. A get-fixture method returns a new instance of a needed fixture object (or an holder object containing multiple fixture objects) each time it is called. You can call a get-fixture method at the beginning of each test that needs the fixture, storing the returned object or objects in local variables. Here's an example:

    package org.scalatest.examples.funsuite.getfixture
    
    import org.scalatest.FunSuite
    import collection.mutable.ListBuffer
    
    class ExampleSuite extends FunSuite {
    
      class Fixture {
        val builder = new StringBuilder("ScalaTest is ")
        val buffer = new ListBuffer[String]
      }
    
      def fixture = new Fixture
    
      test("Testing should be easy") {
        val f = fixture
        f.builder.append("easy!")
        assert(f.builder.toString === "ScalaTest is easy!")
        assert(f.buffer.isEmpty)
        f.buffer += "sweet"
      }
    
      test("Testing should be fun") {
        val f = fixture
        f.builder.append("fun!")
        assert(f.builder.toString === "ScalaTest is fun!")
        assert(f.buffer.isEmpty)
      }
    }
    

    The “f.” in front of each use of a fixture object provides a visual indication of which objects are part of the fixture, but if you prefer, you can import the the members with “import f._” and use the names directly.

    If you need to configure fixture objects differently in different tests, you can pass configuration into the get-fixture method. For example, if you could pass in an initial value for a mutable fixture object as a parameter to the get-fixture method.

    Instantiating fixture-context objects

    An alternate technique that is especially useful when different tests need different combinations of fixture objects is to define the fixture objects as instance variables of fixture-context objects whose instantiation forms the body of tests. Like get-fixture methods, fixture-context objects are only appropriate if you don't need to clean up the fixtures after using them.

    To use this technique, you define instance variables intialized with fixture objects in traits and/or classes, then in each test instantiate an object that contains just the fixture objects needed by the test. Traits allow you to mix together just the fixture objects needed by each test, whereas classes allow you to pass data in via a constructor to configure the fixture objects. Here's an example in which fixture objects are partitioned into two traits and each test just mixes together the traits it needs:

    package org.scalatest.examples.funsuite.fixturecontext
    
    import collection.mutable.ListBuffer
    import org.scalatest.FunSuite
    
    class ExampleSuite extends FunSuite {
    
      trait Builder {
        val builder = new StringBuilder("ScalaTest is ")
      }
    
      trait Buffer {
        val buffer = ListBuffer("ScalaTest", "is")
      }
    
      // This test needs the StringBuilder fixture
      test("Testing should be productive") {
        new Builder {
          builder.append("productive!")
          assert(builder.toString === "ScalaTest is productive!")
        }
      }
    
      // This test needs the ListBuffer[String] fixture
      test("Test code should be readable") {
        new Buffer {
          buffer += ("readable!")
          assert(buffer === List("ScalaTest", "is", "readable!"))
        }
      }
    
      // This test needs both the StringBuilder and ListBuffer
      test("Test code should be clear and concise") {
        new Builder with Buffer {
          builder.append("clear!")
          buffer += ("concise!")
          assert(builder.toString === "ScalaTest is clear!")
          assert(buffer === List("ScalaTest", "is", "concise!"))
        }
      }
    }
    

    Overriding withFixture(NoArgTest)

    Although the get-fixture method and fixture-context object approaches take care of setting up a fixture at the beginning of each test, they don't address the problem of cleaning up a fixture at the end of the test. If you just need to perform a side-effect at the beginning or end of a test, and don't need to actually pass any fixture objects into the test, you can override withFixture(NoArgTest), one of ScalaTest's lifecycle methods defined in trait Suite.

    Trait Suite's implementation of runTest passes a no-arg test function to withFixture(NoArgTest). It is withFixture's responsibility to invoke that test function. Suite's implementation of withFixture simply invokes the function, like this:

    // Default implementation in trait Suite
    protected def withFixture(test: NoArgTest) = {
      test()
    }
    

    You can, therefore, override withFixture to perform setup before and/or cleanup after invoking the test function. If you have cleanup to perform, you should invoke the test function inside a try block and perform the cleanup in a finally clause, in case an exception propagates back through withFixture. (If a test fails because of an exception, the test function invoked by withFixture will result in a Failed wrapping the exception. Nevertheless, best practice is to perform cleanup in a finally clause just in case an exception occurs.)

    The withFixture method is designed to be stacked, and to enable this, you should always call the super implementation of withFixture, 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)”, like this:

    // Your implementation
    override def withFixture(test: NoArgTest) = {
      // Perform setup
      try super.withFixture(test) // Invoke the test function
      finally {
        // Perform cleanup
      }
    }
    

    Here's an example in which withFixture(NoArgTest) is used to take a snapshot of the working directory if a test fails, and send that information to the reporter:

    package org.scalatest.examples.funsuite.noargtest
    
    import java.io.File
    import org.scalatest._
    
    class ExampleSuite extends FunSuite {
    
      override def withFixture(test: NoArgTest) = {
    
        super.withFixture(test) match {
          case failed: Failed =>
            val currDir = new File(".")
            val fileNames = currDir.list()
            info("Dir snapshot: " + fileNames.mkString(", "))
            failed
          case other => other
        }
      }
    
      test("This test should succeed") {
        assert(1 + 1 === 2)
      }
    
      test("This test should fail") {
        assert(1 + 1 === 3)
      }
    }
    

    Running this version of ExampleSuite in the interpreter in a directory with two files, hello.txt and world.txt would give the following output:

    scala> org.scalatest.run(new ExampleSuite)
    ExampleSuite:
    - this test should succeed
    - this test should fail *** FAILED ***
      2 did not equal 3 (:33)
      + Dir snapshot: hello.txt, world.txt 
    

    Note that the NoArgTest passed to withFixture, in addition to an apply method that executes the test, also includes the test name and the config map passed to runTest. Thus you can also use the test name and configuration objects in your withFixture implementation.

    Calling loan-fixture methods

    If you need to both pass a fixture object into a test and perform cleanup at the end of the test, you'll need to use the loan pattern. If different tests need different fixtures that require cleanup, you can implement the loan pattern directly by writing loan-fixture methods. A loan-fixture method takes a function whose body forms part or all of a test's code. It creates a fixture, passes it to the test code by invoking the function, then cleans up the fixture after the function returns.

    The following example shows three tests that use two fixtures, a database and a file. Both require cleanup after, so each is provided via a loan-fixture method. (In this example, the database is simulated with a StringBuffer.)

    package org.scalatest.examples.funsuite.loanfixture
    
    import java.util.concurrent.ConcurrentHashMap
    
    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)
      }
    }
    
    import org.scalatest.FunSuite
    import DbServer._
    import java.util.UUID.randomUUID
    import java.io._
    
    class ExampleSuite extends FunSuite {
    
      def withDatabase(testCode: Db => Any) {
        val dbName = randomUUID.toString
        val db = createDb(dbName) // create the fixture
        try {
          db.append("ScalaTest is ") // perform setup
          testCode(db) // "loan" the fixture to the test
        }
        finally removeDb(dbName) // clean up the fixture
      }
    
      def withFile(testCode: (File, FileWriter) => Any) {
        val file = File.createTempFile("hello", "world") // create the fixture
        val writer = new FileWriter(file)
        try {
          writer.write("ScalaTest is ") // set up the fixture
          testCode(file, writer) // "loan" the fixture to the test
        }
        finally writer.close() // clean up the fixture
      }
    
      // This test needs the file fixture
      test("Testing should be productive") {
        withFile { (file, writer) =>
          writer.write("productive!")
          writer.flush()
          assert(file.length === 24)
        }
      }
    
      // This test needs the database fixture
      test("Test code should be readable") {
        withDatabase { db =>
          db.append("readable!")
          assert(db.toString === "ScalaTest is readable!")
        }
      }
    
      // This test needs both the file and the database
      test("Test code should be clear and concise") {
        withDatabase { db =>
          withFile { (file, writer) => // loan-fixture methods compose
            db.append("clear!")
            writer.write("concise!")
            writer.flush()
            assert(db.toString === "ScalaTest is clear!")
            assert(file.length === 21)
          }
        }
      }
    }
    

    As demonstrated by the last test, loan-fixture methods compose. Not only do loan-fixture methods allow you to give each test the fixture it needs, they allow you to give a test multiple fixtures and clean everything up afterwards.

    Also demonstrated in this example is 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 this example. This keeps tests completely isolated, allowing you to run them in parallel if desired.

    Overriding withFixture(OneArgTest)

    If all or most tests need the same fixture, you can avoid some of the boilerplate of the loan-fixture method approach by using a fixture.Suite and overriding withFixture(OneArgTest). Each test in a fixture.Suite takes a fixture as a parameter, allowing you to pass the fixture into the test. You must indicate the type of the fixture parameter by specifying FixtureParam, and implement a withFixture method that takes a OneArgTest. This withFixture method is responsible for invoking the one-arg test function, so you can perform fixture set up before, and clean up after, invoking and passing the fixture into the test function.

    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)
      }
    }
    

    In this example, the tests actually required two fixture objects, a File and a FileWriter. In such situations you can simply define the FixtureParam type to be a tuple containing the objects, or as is done in this example, a case class containing the objects. For more information on the withFixture(OneArgTest) technique, see the documentation for fixture.FunSuite.

    Mixing in BeforeAndAfter

    In all the shared fixture examples shown so far, the activities of creating, setting up, and cleaning up the fixture objects have been performed during the test. This means that if an exception occurs during any of these activities, it will be reported as a test failure. Sometimes, however, you may want setup to happen before the test starts, and cleanup after the test has completed, so that if an exception occurs during setup or cleanup, the entire suite aborts and no more tests are attempted. The simplest way to accomplish this in ScalaTest is to mix in trait BeforeAndAfter. With this trait you can denote a bit of code to run before each test with before and/or after each test each test with after, like this:

    package org.scalatest.examples.funsuite.beforeandafter
    
    import org.scalatest.FunSuite
    import org.scalatest.BeforeAndAfter
    import collection.mutable.ListBuffer
    
    class ExampleSuite extends FunSuite with BeforeAndAfter {
    
      val builder = new StringBuilder
      val buffer = new ListBuffer[String]
    
      before {
        builder.append("ScalaTest is ")
      }
    
      after {
        builder.clear()
        buffer.clear()
      }
    
      test("testing should be easy") {
        builder.append("easy!")
        assert(builder.toString === "ScalaTest is easy!")
        assert(buffer.isEmpty)
        buffer += "sweet"
      }
    
      test("testing should be fun") {
        builder.append("fun!")
        assert(builder.toString === "ScalaTest is fun!")
        assert(buffer.isEmpty)
      }
    }
    

    Note that the only way before and after code can communicate with test code is via some side-effecting mechanism, commonly by reassigning instance vars or by changing the state of mutable objects held from instance vals (as in this example). If using instance vars or mutable objects held from instance vals you wouldn't be able to run tests in parallel in the same instance of the test class (on the JVM, not Scala.js) unless you synchronized access to the shared, mutable state. This is why ScalaTest's ParallelTestExecution trait extends OneInstancePerTest. By running each test in its own instance of the class, each test has its own copy of the instance variables, so you don't need to synchronize. If you mixed ParallelTestExecution into the ExampleSuite above, the tests would run in parallel just fine without any synchronization needed on the mutable StringBuilder and ListBuffer[String] objects.

    Although BeforeAndAfter provides a minimal-boilerplate way to execute code before and after tests, it isn't designed to enable stackable traits, because the order of execution would be non-obvious. If you want to factor out before and after code that is common to multiple test suites, you should use trait BeforeAndAfterEach instead, as shown later in the next section, composing fixtures by stacking traits.

    Composing fixtures by stacking traits

    In larger projects, teams often end up with several different fixtures that test classes need in different combinations, and possibly initialized (and cleaned up) in different orders. A good way to accomplish this in ScalaTest is to factor the individual fixtures into traits that can be composed using the stackable trait pattern. This can be done, for example, by placing withFixture methods in several traits, each of which call super.withFixture. Here's an example in which the StringBuilder and ListBuffer[String] fixtures used in the previous examples have been factored out into two stackable fixture traits named Builder and Buffer:

    package org.scalatest.examples.funsuite.composingwithfixture
    
    import org.scalatest._
    import collection.mutable.ListBuffer
    
    trait Builder extends TestSuiteMixin { this: TestSuite =>
    
      val builder = new StringBuilder
    
      abstract override def withFixture(test: NoArgTest) = {
        builder.append("ScalaTest is ")
        try super.withFixture(test) // To be stackable, must call super.withFixture
        finally builder.clear()
      }
    }
    
    trait Buffer extends TestSuiteMixin { this: TestSuite =>
    
      val buffer = new ListBuffer[String]
    
      abstract override def withFixture(test: NoArgTest) = {
        try super.withFixture(test) // To be stackable, must call super.withFixture
        finally buffer.clear()
      }
    }
    
    class ExampleSuite extends FunSuite with Builder with Buffer {
    
      test("Testing should be easy") {
        builder.append("easy!")
        assert(builder.toString === "ScalaTest is easy!")
        assert(buffer.isEmpty)
        buffer += "sweet"
      }
    
      test("Testing should be fun") {
        builder.append("fun!")
        assert(builder.toString === "ScalaTest is fun!")
        assert(buffer.isEmpty)
        buffer += "clear"
      }
    }
    

    By mixing in both the Builder and Buffer traits, ExampleSuite gets both fixtures, which will be initialized before each test and cleaned up after. The order the traits are mixed together determines the order of execution. In this case, Builder is “super” to Buffer. If you wanted Buffer to be “super” to Builder, you need only switch the order you mix them together, like this:

    class Example2Suite extends FunSuite with Buffer with Builder
    

    And if you only need one fixture you mix in only that trait:

    class Example3Suite extends FunSuite with Builder
    

    Another way to create stackable fixture traits is by extending the BeforeAndAfterEach and/or BeforeAndAfterAll traits. BeforeAndAfterEach has 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). Similarly, BeforeAndAfterAll has a beforeAll method that will be run before all tests, and an afterAll method that will be run after all tests. Here's what the previously shown example would look like if it were rewritten to use the BeforeAndAfterEach methods instead of withFixture:

    package org.scalatest.examples.funsuite.composingbeforeandaftereach
    
    import org.scalatest._
    import org.scalatest.BeforeAndAfterEach
    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 ExampleSuite extends FunSuite with Builder with Buffer {
    
      test("Testing should be easy") {
        builder.append("easy!")
        assert(builder.toString === "ScalaTest is easy!")
        assert(buffer.isEmpty)
        buffer += "sweet"
      }
    
      test("Testing should be fun") {
        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 difference between stacking traits that extend BeforeAndAfterEach versus traits that implement withFixture is that setup and cleanup code happens before and after the test in BeforeAndAfterEach, but at the beginning and end of the test in withFixture. Thus if a withFixture method completes abruptly with an exception, it is considered a failed test. By contrast, if any of the beforeEach or afterEach methods of BeforeAndAfterEach complete abruptly, it is considered an aborted suite, which will result in a SuiteAborted event.

    Shared tests

    Sometimes you may want to run the same test code on different fixture objects. In other words, you may want to write tests that are "shared" by different fixture objects. To accomplish this in a FunSuite, you first place shared tests in behavior functions. These behavior functions will be invoked during the construction phase of any FunSuite that uses them, so that the tests they contain will be registered as tests in that FunSuite. For example, given this stack class:

    import scala.collection.mutable.ListBuffer
    
    class Stack[T] {
    
      val MAX = 10
      private val buf = new ListBuffer[T]
    
      def push(o: T) {
        if (!full)
          buf.prepend(o)
        else
          throw new IllegalStateException("can't push onto a full stack")
      }
    
      def pop(): T = {
        if (!empty)
          buf.remove(0)
        else
          throw new IllegalStateException("can't pop an empty stack")
      }
    
      def peek: T = {
        if (!empty)
          buf(0)
        else
          throw new IllegalStateException("can't pop an empty stack")
      }
    
      def full: Boolean = buf.size == MAX
      def empty: Boolean = buf.size == 0
      def size = buf.size
    
      override def toString = buf.mkString("Stack(", ", ", ")")
    }
    

    You may want to test the Stack class in different states: empty, full, with one item, with one item less than capacity, etc. You may find you have several tests that make sense any time the stack is non-empty. Thus you'd ideally want to run those same tests for three stack fixture objects: a full stack, a stack with a one item, and a stack with one item less than capacity. With shared tests, you can factor these tests out into a behavior function, into which you pass the stack fixture to use when running the tests. So in your FunSuite for stack, you'd invoke the behavior function three times, passing in each of the three stack fixtures so that the shared tests are run for all three fixtures.

    You can define a behavior function that encapsulates these shared tests inside the FunSuite that uses them. If they are shared between different FunSuites, however, you could also define them in a separate trait that is mixed into each FunSuite that uses them. For example, here the nonEmptyStack behavior function (in this case, a behavior method) is defined in a trait along with another method containing shared tests for non-full stacks:

    import org.scalatest.FunSuite
    
    trait FunSuiteStackBehaviors { this: FunSuite =>
    
      def nonEmptyStack(createNonEmptyStack: => Stack[Int], lastItemAdded: Int) {
    
        test("empty is invoked on this non-empty stack: " + createNonEmptyStack.toString) {
          val stack = createNonEmptyStack
          assert(!stack.empty)
        }
    
        test("peek is invoked on this non-empty stack: " + createNonEmptyStack.toString) {
          val stack = createNonEmptyStack
          val size = stack.size
          assert(stack.peek === lastItemAdded)
          assert(stack.size === size)
        }
    
        test("pop is invoked on this non-empty stack: " + createNonEmptyStack.toString) {
          val stack = createNonEmptyStack
          val size = stack.size
          assert(stack.pop === lastItemAdded)
          assert(stack.size === size - 1)
        }
      }
    
      def nonFullStack(createNonFullStack: => Stack[Int]) {
    
        test("full is invoked on this non-full stack: " + createNonFullStack.toString) {
          val stack = createNonFullStack
          assert(!stack.full)
        }
    
        test("push is invoked on this non-full stack: " + createNonFullStack.toString) {
          val stack = createNonFullStack
          val size = stack.size
          stack.push(7)
          assert(stack.size === size + 1)
          assert(stack.peek === 7)
        }
      }
    }
    

    Given these behavior functions, you could invoke them directly, but FunSuite offers a DSL for the purpose, which looks like this:

    testsFor(nonEmptyStack(stackWithOneItem, lastValuePushed))
    testsFor(nonFullStack(stackWithOneItem))
    

    If you prefer to use an imperative style to change fixtures, for example by mixing in BeforeAndAfterEach and reassigning a stack var in beforeEach, you could write your behavior functions in the context of that var, which means you wouldn't need to pass in the stack fixture because it would be in scope already inside the behavior function. In that case, your code would look like this:

    testsFor(nonEmptyStack) // assuming lastValuePushed is also in scope inside nonEmptyStack
    testsFor(nonFullStack)
    

    The recommended style, however, is the functional, pass-all-the-needed-values-in style. Here's an example:

    import org.scalatest.FunSuite
    
    class StackFunSuite extends FunSuite with FunSuiteStackBehaviors {
    
      // Stack fixture creation methods
      def emptyStack = new Stack[Int]
    
      def fullStack = {
        val stack = new Stack[Int]
        for (i <- 0 until stack.MAX)
          stack.push(i)
        stack
      }
    
      def stackWithOneItem = {
        val stack = new Stack[Int]
        stack.push(9)
        stack
      }
    
      def stackWithOneItemLessThanCapacity = {
        val stack = new Stack[Int]
        for (i <- 1 to 9)
          stack.push(i)
        stack
      }
    
      val lastValuePushed = 9
    
      test("empty is invoked on an empty stack") {
        val stack = emptyStack
        assert(stack.empty)
      }
    
      test("peek is invoked on an empty stack") {
        val stack = emptyStack
        assertThrows[IllegalStateException] {
          stack.peek
        }
      }
    
      test("pop is invoked on an empty stack") {
        val stack = emptyStack
        assertThrows[IllegalStateException] {
          stack.pop
        }
      }
    
      testsFor(nonEmptyStack(stackWithOneItem, lastValuePushed))
      testsFor(nonFullStack(stackWithOneItem))
    
      testsFor(nonEmptyStack(stackWithOneItemLessThanCapacity, lastValuePushed))
      testsFor(nonFullStack(stackWithOneItemLessThanCapacity))
    
      test("full is invoked on a full stack") {
        val stack = fullStack
        assert(stack.full)
      }
    
      testsFor(nonEmptyStack(fullStack, lastValuePushed))
    
      test("push is invoked on a full stack") {
        val stack = fullStack
        assertThrows[IllegalStateException] {
          stack.push(10)
        }
      }
    }
    

    If you load these classes into the Scala interpreter (with scalatest's JAR file on the class path), and execute it, you'll see:

    scala> org.scalatest.run(new StackFunSuite)
    StackFunSuite:
    - empty is invoked on an empty stack
    - peek is invoked on an empty stack
    - pop is invoked on an empty stack
    - empty is invoked on this non-empty stack: Stack(9)
    - peek is invoked on this non-empty stack: Stack(9)
    - pop is invoked on this non-empty stack: Stack(9)
    - full is invoked on this non-full stack: Stack(9)
    - push is invoked on this non-full stack: Stack(9)
    - empty is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1)
    - peek is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1)
    - pop is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1)
    - full is invoked on this non-full stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1)
    - push is invoked on this non-full stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1)
    - full is invoked on a full stack
    - empty is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
    - peek is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
    - pop is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
    - push is invoked on a full stack
    

    One thing to keep in mind when using shared tests is that in ScalaTest, each test in a suite must have a unique name. If you register the same tests repeatedly in the same suite, one problem you may encounter is an exception at runtime complaining that multiple tests are being registered with the same test name. In a FunSuite there is no nesting construct analogous to FunSpec's describe clause. Therefore, you need to do a bit of extra work to ensure that the test names are unique. If a duplicate test name problem shows up in a FunSuite, you'll need to pass in a prefix or suffix string to add to each test name. You can pass this string the same way you pass any other data needed by the shared tests, or just call toString on the shared fixture object. This is the approach taken by the previous FunSuiteStackBehaviors example.

    Given this FunSuiteStackBehaviors trait, calling it with the stackWithOneItem fixture, like this:

    testsFor(nonEmptyStack(stackWithOneItem, lastValuePushed))
    

    yields test names:

    • empty is invoked on this non-empty stack: Stack(9)
    • peek is invoked on this non-empty stack: Stack(9)
    • pop is invoked on this non-empty stack: Stack(9)

    Whereas calling it with the stackWithOneItemLessThanCapacity fixture, like this:

    testsFor(nonEmptyStack(stackWithOneItemLessThanCapacity, lastValuePushed))
    

    yields different test names:

    • empty is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1)
    • peek is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1)
    • pop is invoked on this non-empty stack: Stack(9, 8, 7, 6, 5, 4, 3, 2, 1)
    Annotations
    @Finders()
  58. trait FunSuiteLike extends TestSuite with TestRegistration with Informing with Notifying with Alerting with Documenting

    Permalink

    Implementation trait for class FunSuite, which represents a suite of tests in which each test is represented as a function value.

    Implementation trait for class FunSuite, which represents a suite of tests in which each test is represented as a function value.

    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 FunSuite into some other class, you can use this trait instead, because class 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 FunSuite.

    Annotations
    @Finders() @JSExportDescendentClasses( true )
  59. class FutureOutcome extends AnyRef

    Permalink

    Wrapper class for Future[Outcome] that presents a more convenient API for manipulation in withFixture methods in async styles.

    Wrapper class for Future[Outcome] that presents a more convenient API for manipulation in withFixture methods in async styles.

    This type serves as the result type of both test functions and withFixture methods in ScalaTest's async styles. A Future[Outcome] is not used as this result type for two reasons. First, Outcome treats exceptions specially, and as a result methods on Future would usually not yield the desired Future[Outcome] result. Only run-aborting exceptions should result in a failed Future[Outcome]. Any other thrown exception other than TestCanceledException or TestPendingException should result in a successfulFuture containing a org.scalatest.Failed. A thrown TestCanceledException should result in a successful Future containing an org.scalatest.Canceled; A thrown TestPendingException should result in a successful Future containing a org.scalatest.Pending. If manipulating a Future[Outcome] directly, by contrast, any thrown exception would result in a failed Future.

    Additionally, to be consistent with corresponding transformations in traditional testing styles, methods registering callbacks should return a new future outcome that doesn't complete until both the original future outcome has completed and the subsequent callback has completed execution. Additionally, if the callback itself throws an exception, that exception should determine the result of the future outcome returned by the callback registration method. This behavior is rather inconvenient to obtain on the current Future API, so FutureOutcome provides well-named methods that have this behavior.

    Lastly, the FutureOutcome is intended to help prevent confusion by eliminating the need to work with types like scala.util.Success(org.scalatest.Failed). For this purpose a org.scalactic.Or is used instead of a scala.util.Try to describe results of FutureOutcome.

    A FutureOutcome represents a computation that can result in an Outcome or an "abort." An abort means that a run-aborting exception occurred during the computation. Any other, non-run-aborting exception will be represented as an non-Succeeded Outcome: one of Failed, Canceled, or Pending.

    The methods of FutureOutcome include the following callback registration methods:

    • onSucceededThen - registers a callback to be executed if the future outcome is Succeeded.
    • onFailedThen - registers a callback to be executed if the future outcome is Failed.
    • onCanceledThen - registers a callback to be executed if the future outcome is Canceled.
    • onPendingThen - registers a callback to be executed if the future outcome is Pending.
    • onOutcomeThen - registers a callback to be executed if the future outcome is actually an Outcome and not an abort.
    • onAbortedThen - registers a callback to be executed if the future outcome aborts.
    • onCompletedThen - registers a callback to be executed upon completion no matter how the future outcome completes.

    The callback methods listed previously can be used to perform a side effect once a FutureOutcome completes. To change an Outcome into a different Outcome asynchronously, use the change registration method, which takes a function from Outcome to Outcome. The other methods on FutureOutcome, isCompleted and value, allow you to poll a FutureOutcome. None of the methods on FutureOutcome block. Lastly, because an implicit Futuristic instance is provided for FutureOutcome, you can use complete-lastly syntax with FutureOutcome.

  60. trait GivenWhenThen extends AnyRef

    Permalink

    Trait that contains methods named given, when, then, and and, which take a string message and implicit