ScalaTest is a comprehensive testing framework for Scala and Java programmers with multiple testing styles and powerful matcher support.
ScalaTest provides multiple testing styles to accommodate different preferences and project requirements. Each style offers a different syntax and organization approach while sharing the same underlying execution engine.
Function-based testing style with named test functions.
abstract class AnyFunSuite extends Suite with TestSuite with Assertions with TestRegistration {
/**
* Register a test with the given spec text and test function value
*/
protected def test(testName: String)(testFun: => Any): Unit
/**
* Register a test to ignore with the given spec text
*/
protected def ignore(testName: String)(testFun: => Any): Unit
}Usage Example:
import org.scalatest.funsuite.AnyFunSuite
class ExampleFunSuite extends AnyFunSuite {
test("pop is invoked on a non-empty stack") {
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
val oldSize = stack.size
val result = stack.pop()
assert(result === 2)
assert(stack.size === oldSize - 1)
}
ignore("pop is invoked on an empty stack") {
val emptyStack = new Stack[Int]
intercept[IllegalArgumentException] {
emptyStack.pop()
}
}
}Behavior-driven development style with "should" syntax.
abstract class AnyFlatSpec extends Suite with TestSuite with Assertions with TestRegistration {
/**
* Class that supports the registration of tests in shorthand form
*/
protected final class FlatSpecStringWrapper(string: String) {
def should(testFun: => Any): Unit
def must(testFun: => Any): Unit
def can(testFun: => Any): Unit
}
/**
* Implicitly converts strings to FlatSpecStringWrapper for test registration
*/
protected implicit def convertToFlatSpecStringWrapper(o: String): FlatSpecStringWrapper
/**
* Register a test to ignore
*/
protected def ignore: IgnoreWord
}Usage Example:
import org.scalatest.flatspec.AnyFlatSpec
class ExampleFlatSpec extends AnyFlatSpec {
"A Stack" should "pop values in last-in-first-out order" in {
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
assert(stack.pop() === 2)
assert(stack.pop() === 1)
}
it should "throw IllegalArgumentException if pop is invoked on an empty stack" in {
val emptyStack = new Stack[String]
intercept[IllegalArgumentException] {
emptyStack.pop()
}
}
ignore should "be ignored" in {
// This test will be ignored
}
}Ruby RSpec-like nested describe/it syntax.
abstract class AnyFunSpec extends Suite with TestSuite with Assertions with TestRegistration {
/**
* Register a description of the subject being specified and tested
*/
protected def describe(description: String)(fun: => Unit): Unit
/**
* Register a specification/test for the subject being described
*/
protected def it(specText: String)(testFun: => Any): Unit
/**
* Register a test to ignore
*/
protected def ignore(testName: String)(testFun: => Any): Unit
}Usage Example:
import org.scalatest.funspec.AnyFunSpec
class ExampleFunSpec extends AnyFunSpec {
describe("A Stack") {
describe("when not empty") {
it("should remove and return the top item on pop") {
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
assert(stack.pop() === 2)
}
}
describe("when empty") {
it("should throw IllegalArgumentException on pop") {
val emptyStack = new Stack[Int]
intercept[IllegalArgumentException] {
emptyStack.pop()
}
}
}
}
}Specification style with subject-verb-object structure.
abstract class AnyWordSpec extends Suite with TestSuite with Assertions with TestRegistration {
/**
* Class that supports the registration of subjects
*/
protected final class WordSpecStringWrapper(string: String) {
def when(f: => Unit): Unit
def which(f: => Unit): Unit
def should(f: => Unit): Unit
def must(f: => Unit): Unit
def can(f: => Unit): Unit
}
/**
* Implicitly converts strings to WordSpecStringWrapper
*/
protected implicit def convertToWordSpecStringWrapper(s: String): WordSpecStringWrapper
}Usage Example:
import org.scalatest.wordspec.AnyWordSpec
class ExampleWordSpec extends AnyWordSpec {
"A Stack" when {
"not empty" should {
"return the last item added on pop" in {
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
assert(stack.pop() === 2)
}
}
"empty" should {
"throw IllegalArgumentException on pop" in {
val emptyStack = new Stack[Int]
intercept[IllegalArgumentException] {
emptyStack.pop()
}
}
}
}
}Free-form specification style allowing arbitrary nesting.
abstract class AnyFreeSpec extends Suite with TestSuite with Assertions with TestRegistration {
/**
* Class that supports the registration of free-form text with nested tests/scopes
*/
protected final class FreeSpecStringWrapper(string: String) {
def in(f: => Any): Unit
def is(f: => Unit): Unit
def ignore(f: => Any): Unit
}
/**
* Implicitly converts strings to FreeSpecStringWrapper
*/
protected implicit def convertToFreeSpecStringWrapper(s: String): FreeSpecStringWrapper
}Usage Example:
import org.scalatest.freespec.AnyFreeSpec
class ExampleFreeSpec extends AnyFreeSpec {
"A Stack" - {
"when not empty" - {
"should pop values in LIFO order" in {
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
assert(stack.pop() === 2)
assert(stack.pop() === 1)
}
}
"when empty" - {
"should throw on pop" in {
val emptyStack = new Stack[Int]
intercept[IllegalArgumentException] {
emptyStack.pop()
}
}
}
}
}Property-based testing style for specifying properties that should hold.
abstract class AnyPropSpec extends Suite with TestSuite with Assertions with TestRegistration {
/**
* Register a property-based test
*/
protected def property(testName: String)(testFun: => Any): Unit
/**
* Register a property-based test to ignore
*/
protected def ignore(testName: String)(testFun: => Any): Unit
}Usage Example:
import org.scalatest.propspec.AnyPropSpec
import org.scalatest.prop.PropertyChecks
class ExamplePropSpec extends AnyPropSpec with PropertyChecks {
property("list size should equal the number of elements added") {
forAll { (list: List[Int]) =>
val buffer = scala.collection.mutable.ListBuffer.empty[Int]
list.foreach(buffer += _)
assert(buffer.size === list.size)
}
}
property("reversing a list twice should give the original list") {
forAll { (list: List[String]) =>
assert(list.reverse.reverse === list)
}
}
}Acceptance testing style with Given-When-Then structure.
abstract class AnyFeatureSpec extends Suite with TestSuite with Assertions with TestRegistration {
/**
* Register a feature (user story or requirement)
*/
protected def feature(description: String)(fun: => Unit): Unit
/**
* Register a scenario within a feature
*/
protected def scenario(description: String)(fun: => Any): Unit
/**
* Register a scenario to ignore
*/
protected def ignore(description: String)(fun: => Any): Unit
/**
* Provides Given step syntax
*/
protected def Given(description: String): Unit
/**
* Provides When step syntax
*/
protected def When(description: String): Unit
/**
* Provides Then step syntax
*/
protected def Then(description: String): Unit
/**
* Provides And step syntax
*/
protected def And(description: String): Unit
}Usage Example:
import org.scalatest.featurespec.AnyFeatureSpec
import org.scalatest.GivenWhenThen
class ExampleFeatureSpec extends AnyFeatureSpec with GivenWhenThen {
feature("Stack operations") {
scenario("User pops an element from a non-empty stack") {
Given("a non-empty stack")
val stack = new Stack[String]
stack.push("item1")
stack.push("item2")
When("the user pops an element")
val poppedElement = stack.pop()
Then("the most recently pushed element should be returned")
assert(poppedElement === "item2")
And("the stack size should be reduced by one")
assert(stack.size === 1)
}
}
}trait TestRegistration {
def registerTest(testName: String, testTags: Tag*)(testFun: => Any): Unit
def registerIgnoredTest(testName: String, testTags: Tag*)(testFun: => Any): Unit
}
trait TestSuite extends Suite {
def testNames: Set[String]
def tags: Map[String, Set[String]]
def runTest(testName: String, args: Args): Status
}Install with Tessl CLI
npx tessl i tessl/maven-org-scalatest--scalatest-2-13