Getting started with FunSpec

By learning to use FunSpec, simple assertions, and the BeforeAndAfter trait, you can become productive in the BDD style of ScalaTest very quickly. You can then learn and use more of ScalaTest over time.

In a FunSpec, you combine tests with text that specifies the behavior being tested. You can describe the subject being specified and tested with describe clauses and place text that describes the behavior expected of the subject in it clauses. The code of the test appears in curly braces after the it and its text. The structure looks like this:

import org.scalatest.funspec.AnyFunSpec

class ExampleSpec extends AnyFunSpec {

  describe("A Stack") {

    it("should pop values in last-in-first-out order") (pending)

    it("should throw NoSuchElementException if an empty stack is popped") (pending)
  }
}

Here the subject being specified and tested is “A Stack.” The tests are marked pending in the previous example to indicate the tests have not yet been implemented. You can compile this FunSpec like this:

$ scalac -cp scalatest-3.2.18.jar ExampleSpec.scala

Here's how you run it:

$ scala -cp scalatest-3.2.18.jar org.scalatest.run ExampleSpec
Run starting. Expected test count is: 2
ExampleSpec:
A Stack 
- should pop values in last-in-first-out order (pending)
- should throw NoSuchElementException if an empty stack is popped (pending)
Run completed in 61 milliseconds.
Total number of tests run: 0
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 0, ignored 0, pending 2
All tests passed.

Notice that the specification text appears in a readable form in the output. You could fill in the tests like this:

import org.scalatest.funspec.AnyFunSpec
import scala.collection.mutable.Stack

class ExampleSpec extends AnyFunSpec {

  describe("A Stack") {

    it("should pop values in last-in-first-out order") {
      val stack = new Stack[Int]
      stack.push(1)
      stack.push(2)
      assert(stack.pop() === 2)
      assert(stack.pop() === 1)
    }

    it("should throw NoSuchElementException if an empty stack is popped") {
      val emptyStack = new Stack[Int]
      intercept[NoSuchElementException] {
        emptyStack.pop()
      }
    }
  }
}

Now when you run ExampleSpec you'll see the tests are no longer reported as pending:

$ scala -cp scalatest-3.2.18.jar org.scalatest.run ExampleSpec
Run starting. Expected test count is: 2
ExampleSpec:
A Stack 
- should pop values in last-in-first-out order
- should throw NoSuchElementException if an empty stack is popped
Run completed in 76 milliseconds.
Total number of tests run: 2
Suites: completed 1, aborted 0
Tests: succeeded 2, failed 0, ignored 0, pending 0
All tests passed.

Using assertions

To get started quickly with ScalaTest, learn to use assert with the === operator and intercept. Later if you prefer you can switch to ScalaTest's matchers.

ScalaTest lets you use Scala's assertion syntax, but defines a triple equals operator (===) to give you better error messages. The following code would give you an error indicating only that an assertion failed:

assert(1 == 2)

Using triple equals instead would give you the more informative error message, "1 did not equal 2":

assert(1 === 2)

To test whether a bit of code produces an expected exception, use intercept. Place the expected exception type in square brackets after intercept, and the bit of code in curly braces, like this:

val s = "hi"
intercept[IndexOutOfBoundsException] {
  s.charAt(-1)
}

If the bit of code between the curly braces throws the expected exception, intercept will return it. In the previous example that return value was ignored. If you want to inspect the thrown exception, you can do so like this:

val s = "hi"
val thrown = intercept[IndexOutOfBoundsException] {
  s.charAt(-1)
}
assert(thrown.getMessage === "String index out of range: -1")

If the bit of code between the curly braces throws the wrong exception, or does not throw any exception, you'll get a test failure describing the problem.

Factoring out duplicate code

If you want to factor out duplicate code from tests, mix in BeforeAndAfter, surround the code you want to run before each test by before { ... }, and after each test by after { ... }. Here's an example that just uses before:

import org.scalatest.funspec.AnyFunSpec
import org.scalatest.BeforeAndAfter
import scala.collection.mutable.Stack

class ExampleSpec extends AnyFunSpec with BeforeAndAfter {

  var stack: Stack[Int] = _

  before {
    stack = new Stack[Int]
  }

  describe("A Stack") {

    it("should pop values in last-in-first-out order") {
      stack.push(1)
      stack.push(2)
      assert(stack.pop() === 2)
      assert(stack.pop() === 1)
    }

    it("should throw NoSuchElementException if an empty stack is popped") {
      intercept[NoSuchElementException] {
        stack.pop()
      }
    }
  }
}

You compile and run it the same way:

$ scalac -cp scalatest-3.2.18.jar ExampleSpec.scala
$ scala -cp scalatest-3.2.18.jar org.scalatest.run ExampleSpec
Run starting. Expected test count is: 2
ExampleSpec:
A Stack 
- should pop values in last-in-first-out order
- should throw NoSuchElementException if an empty stack is popped
Run completed in 76 milliseconds.
Total number of tests run: 2
Suites: completed 1, aborted 0
Tests: succeeded 2, failed 0, ignored 0, pending 0
All tests passed.

Armed with this knowledge, you can already write real BDD-style tests with ScalaTest. To go further, check out the user guide.

ScalaTest is brought to you by Bill Venners and Artima.
ScalaTest is free, open-source software released under the Apache 2.0 license.

If your company loves ScalaTest, please consider sponsoring the project.

Copyright © 2009-2024 Artima, Inc. All Rights Reserved.

artima