ScalaTest is a comprehensive testing framework for Scala and Java that provides multiple testing styles and sophisticated matcher libraries.
—
ScalaTest provides comprehensive test execution capabilities including programmatic execution, command-line runners, build tool integration, and extensive configuration options. The framework supports parallel execution, filtering, reporting, and integration with various development environments.
Execute tests directly from Scala code with full control over configuration.
import org.scalatest._
// Main execution entry point
object run {
def main(args: Array[String]): Unit
def apply(
suite: Suite,
testName: String = null,
configMap: ConfigMap = ConfigMap.empty,
color: Boolean = true,
durations: Boolean = false,
shortstacks: Boolean = false,
fullstacks: Boolean = false,
stats: Boolean = false
): Unit
}
// Suite execution methods
trait Suite {
def run(testName: Option[String], args: Args): Status
def execute(
testName: Option[String] = None,
configMap: ConfigMap = ConfigMap.empty,
color: Boolean = true,
durations: Boolean = false,
shortstacks: Boolean = false,
fullstacks: Boolean = false,
stats: Boolean = false,
reporter: Reporter = new StandardOutReporter,
stopper: Stopper = Stopper.default,
filter: Filter = Filter(),
tracker: Tracker = new Tracker,
chosenStyles: Set[String] = Set.empty,
runTestInNewInstance: Boolean = false,
distributor: Option[Distributor] = None,
summaryCounter: SummaryCounter = new SummaryCounter
): Status
}Programmatic Execution Examples:
import org.scalatest._
import org.scalatest.funsuite.AnyFunSuite
class MySuite extends AnyFunSuite {
test("example test") {
assert(1 + 1 === 2)
}
}
// Simple execution
run(new MySuite)
// Execution with configuration
val suite = new MySuite
suite.execute(
configMap = ConfigMap("env" -> "test"),
color = true,
durations = true,
stats = true
)
// Execute specific test
suite.execute(testName = Some("example test"))Execute tests from the command line with extensive configuration options.
import org.scalatest.tools._
object Runner {
def main(args: Array[String]): Unit
def run(args: Array[String]): Boolean
}
// Common command-line arguments:
// -o : StandardOutReporter
// -e : StandardErrReporter
// -f <filename> : FileReporter
// -u <directory> : JunitXmlReporter
// -h <filename> : HtmlReporter
// -n <tag> : Include only tests with tag
// -l <tag> : Exclude tests with tag
// -s <classname> : Run specific suite
// -j <classname> : Run with JUnitRunner
// -m <classname> : Run specific member (test)
// -w <package> : Wildcard package discovery
// -q : Suppress reminder message
// -S : Enable short stack traces
// -F : Enable full stack traces
// -T : Show durations
// -C : Disable ANSI color
// -D : Show all durationsCommand-Line Examples:
# Run all tests with console output
scala -cp <classpath> org.scalatest.tools.Runner -o
# Run specific suite
scala -cp <classpath> org.scalatest.tools.Runner -s com.example.MySuite -o
# Run tests with HTML report
scala -cp <classpath> org.scalatest.tools.Runner -o -h reports/test-results.html
# Run tests with JUnit XML output
scala -cp <classpath> org.scalatest.tools.Runner -o -u target/test-reports
# Run tests with specific tags
scala -cp <classpath> org.scalatest.tools.Runner -n FastTest -l SlowTest -o
# Run with parallel execution and durations
scala -cp <classpath> org.scalatest.tools.Runner -P -T -oConfigure test execution behavior through Args and ConfigMap.
// Test execution arguments
case class Args(
reporter: Reporter,
stopper: Stopper,
filter: Filter,
configMap: ConfigMap,
distributor: Option[Distributor],
tracker: Tracker,
chosenStyles: Set[String],
runTestInNewInstance: Boolean,
distributedTestSorter: Option[DistributedTestSorter],
summaryCounter: SummaryCounter
)
// Configuration map for passing data to tests
type ConfigMap = Map[String, Any]
object ConfigMap {
def empty: ConfigMap = Map.empty
def apply(entries: (String, Any)*): ConfigMap = Map(entries: _*)
}
// Test filtering
class Filter(
tagsToInclude: Option[Set[String]] = None,
tagsToExclude: Set[String] = Set.empty,
excludeNestedSuites: Boolean = false,
dynaTags: DynaTags = DynaTags(Map.empty, Map.empty)
)
// Execution control
trait Stopper {
def stopRequested: Boolean
def requestStop(): Unit
}Configuration Examples:
import org.scalatest._
// Custom configuration map
val config = ConfigMap(
"db.url" -> "jdbc:h2:mem:test",
"timeout" -> 30,
"env" -> "test"
)
// Custom filter - include FastTest, exclude SlowTest
val filter = Filter(
tagsToInclude = Some(Set("FastTest")),
tagsToExclude = Set("SlowTest")
)
// Custom args with configuration
val args = Args(
reporter = new StandardOutReporter,
stopper = Stopper.default,
filter = filter,
configMap = config,
distributor = None,
tracker = new Tracker,
chosenStyles = Set.empty,
runTestInNewInstance = false,
distributedTestSorter = None,
summaryCounter = new SummaryCounter
)
// Use configuration in test
class ConfigurableTest extends AnyFunSuite {
test("uses configuration") {
val dbUrl = testOptions.configMap.getOrElse("db.url", "default-url")
assert(dbUrl === "jdbc:h2:mem:test")
}
}Various output formats for test results.
import org.scalatest.tools._
// Base reporter trait
trait Reporter {
def apply(event: Event): Unit
}
// Built-in reporters
class StandardOutReporter extends Reporter
class StandardErrReporter extends Reporter
class FileReporter(fileName: String) extends Reporter
class HtmlReporter(directory: String) extends Reporter
class JunitXmlReporter(directory: String) extends Reporter
class XmlReporter(fileName: String) extends Reporter
class MemoryReporter extends Reporter {
def eventsReceived: IndexedSeq[Event]
}
// Composite reporter for multiple outputs
class MultipleReporter(reporters: Reporter*) extends Reporter
// Graphic reporter for GUI output
class GraphicReporter extends ReporterReporter Examples:
import org.scalatest.tools._
// Multiple reporters
val reporters = List(
new StandardOutReporter,
new HtmlReporter("target/test-reports"),
new JunitXmlReporter("target/junit-reports"),
new FileReporter("test-results.txt")
)
val multiReporter = new MultipleReporter(reporters: _*)
// Memory reporter for programmatic access to results
val memoryReporter = new MemoryReporter
suite.execute(reporter = memoryReporter)
// Access collected events
val events = memoryReporter.eventsReceived
val failures = events.collect { case tf: TestFailed => tf }
val successes = events.collect { case ts: TestSucceeded => ts }Events generated during test execution for reporting and monitoring.
import org.scalatest.events._
// Base event types
sealed abstract class Event {
val ordinal: Ordinal
val presenter: Option[Presenter]
val location: Option[Location]
val message: String
val formatter: Option[Formatter]
val payload: Option[Any]
val threadName: String
val timeStamp: Long
}
// Test lifecycle events
case class RunStarting(
testCount: Int,
configMap: ConfigMap,
formatter: Option[Formatter],
location: Option[Location],
payload: Option[Any],
threadName: String,
timeStamp: Long
) extends Event
case class SuiteStarting(
suiteName: String,
suiteId: String,
suiteClassName: Option[String],
formatter: Option[Formatter],
location: Option[Location],
rerunnable: Option[String],
payload: Option[Any],
threadName: String,
timeStamp: Long
) extends Event
case class TestStarting(
suiteName: String,
suiteId: String,
suiteClassName: Option[String],
testName: String,
testText: String,
formatter: Option[Formatter],
location: Option[Location],
rerunnable: Option[String],
payload: Option[Any],
threadName: String,
timeStamp: Long
) extends Event
// Test result events
case class TestSucceeded(
suiteName: String,
suiteId: String,
suiteClassName: Option[String],
testName: String,
testText: String,
recordedEvents: IndexedSeq[RecordableEvent],
duration: Option[Long],
formatter: Option[Formatter],
location: Option[Location],
rerunnable: Option[String],
payload: Option[Any],
threadName: String,
timeStamp: Long
) extends Event
case class TestFailed(
message: String,
suiteName: String,
suiteId: String,
suiteClassName: Option[String],
testName: String,
testText: String,
recordedEvents: IndexedSeq[RecordableEvent],
throwable: Option[Throwable],
duration: Option[Long],
formatter: Option[Formatter],
location: Option[Location],
rerunnable: Option[String],
payload: Option[Any],
threadName: String,
timeStamp: Long
) extends Event
case class TestIgnored(
suiteName: String,
suiteId: String,
suiteClassName: Option[String],
testName: String,
testText: String,
formatter: Option[Formatter],
location: Option[Location],
payload: Option[Any],
threadName: String,
timeStamp: Long
) extends Event
case class TestPending(
suiteName: String,
suiteId: String,
suiteClassName: Option[String],
testName: String,
testText: String,
recordedEvents: IndexedSeq[RecordableEvent],
duration: Option[Long],
formatter: Option[Formatter],
location: Option[Location],
payload: Option[Any],
threadName: String,
timeStamp: Long
) extends Event
case class TestCanceled(
message: String,
suiteName: String,
suiteId: String,
suiteClassName: Option[String],
testName: String,
testText: String,
recordedEvents: IndexedSeq[RecordableEvent],
throwable: Option[Throwable],
duration: Option[Long],
formatter: Option[Formatter],
location: Option[Location],
payload: Option[Any],
threadName: String,
timeStamp: Long
) extends EventTrack test execution progress and results.
// Execution status
sealed trait Status {
def isCompleted: Boolean
def succeeds(): Boolean
def unreportedException: Option[Throwable]
def whenCompleted(f: Boolean => Unit): Unit
def waitUntilCompleted(): Unit
}
// Status implementations
case object SucceededStatus extends Status {
val isCompleted = true
def succeeds() = true
val unreportedException = None
}
case class FailedStatus(ex: Throwable) extends Status {
val isCompleted = true
def succeeds() = false
val unreportedException = Some(ex)
}
class StatefulStatus extends Status {
def setCompleted(): Unit
def setFailed(ex: Throwable): Unit
def waitUntilCompleted(): Unit
}
// Result counting
class SummaryCounter {
def testsSucceededCount: Int
def testsFailedCount: Int
def testsIgnoredCount: Int
def testsPendingCount: Int
def testsCanceledCount: Int
def suitesCompletedCount: Int
def suitesAbortedCount: Int
def scopesPendingCount: Int
}Execute tests in parallel for better performance.
// Distributor for parallel execution
trait Distributor {
def apply(suite: Suite, args: Args): Status
def apply(suite: Suite, tracker: Tracker): Unit
}
// Parallel execution configuration
class ParallelTestExecution extends Distributor
// Suite-level parallel execution
trait ParallelTestExecution { this: Suite =>
// Mixed into suite to enable parallel test execution
}
// Async execution for Future-based tests
trait AsyncTestExecution { this: Suite =>
// Mixed into suite to enable async test execution
}Parallel Execution Examples:
import org.scalatest._
import org.scalatest.funsuite.AnyFunSuite
// Enable parallel execution for suite
class ParallelSuite extends AnyFunSuite with ParallelTestExecution {
test("parallel test 1") {
// This test can run in parallel with others
Thread.sleep(100)
assert(true)
}
test("parallel test 2") {
// This test can run in parallel with others
Thread.sleep(100)
assert(true)
}
}
// Command-line parallel execution
// scala -cp <classpath> org.scalatest.tools.Runner -P -oIntegration with SBT, Maven, and other build tools.
// SBT Framework implementation
class Framework extends sbt.testing.Framework {
def name(): String = "ScalaTest"
def fingerprints(): Array[sbt.testing.Fingerprint]
def runner(args: Array[String], remoteArgs: Array[String], testClassLoader: ClassLoader): sbt.testing.Runner
}
// JUnit integration
class JUnitRunner(clazz: Class[_ <: Suite]) extends org.junit.runner.Runner {
def run(notifier: RunNotifier): Unit
def getDescription: Description
}
// TestNG integration
class TestNGSuite extends Suite with TestNGSuiteLikeSBT Integration Example:
// build.sbt
libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.19" % Test
// SBT test command runs ScalaTest
// sbt test
// SBT test configuration
Test / testOptions += Tests.Argument(TestFrameworks.ScalaTest, "-o")
Test / testOptions += Tests.Argument(TestFrameworks.ScalaTest, "-h", "target/test-reports")
// Parallel execution in SBT
Test / parallelExecution := trueDiscover and run tests dynamically.
// Suite discovery
object SuiteDiscoveryHelper {
def discoverSuiteNames(
loader: ClassLoader,
packageNames: List[String],
accessibleSuites: Set[String],
wildcard: Boolean,
runpathClassLoader: ClassLoader
): Set[String]
}
// Dynamic suite creation
trait Suite {
def nestedSuites: IndexedSeq[Suite]
def run(testName: Option[String], args: Args): Status
}Interactive shell for running tests in REPL environments.
// Shell configuration objects (JVM only)
lazy val color: Shell // Enable colored output
lazy val durations: Shell // Show test durations
lazy val shortstacks: Shell // Show short stack traces
lazy val fullstacks: Shell // Show full stack traces
lazy val stats: Shell // Show statistics
lazy val nocolor: Shell // Disable colored output
lazy val nodurations: Shell // Hide test durations
lazy val nostacks: Shell // Hide stack traces
lazy val nostats: Shell // Hide statistics
// Shell trait
trait Shell {
def run(testName: String, reporter: Reporter, stopper: Stopper,
filter: Filter, configMap: ConfigMap, distributor: Option[Distributor],
tracker: Tracker): Unit
}Shell Examples:
// In Scala REPL
import org.scalatest._
// Run with colored output and durations
color.durations.run(new MySuite)
// Run specific test
run(new MySuite, "specific test name")
// Run with custom configuration
run(new MySuite, configMap = ConfigMap("env" -> "test"))Install with Tessl CLI
npx tessl i tessl/maven-org-scalatest--scalatest-2-11