ScalaTest provides multiple testing styles to accommodate different testing preferences, team cultures, and domain-specific languages. Each style offers a different DSL for organizing and writing tests while sharing the same underlying execution engine and assertion capabilities.
xUnit-style testing with named test functions. Ideal for unit testing and teams familiar with JUnit/TestNG.
/**
* Function-based test suite similar to xUnit frameworks
*/
abstract class AnyFunSuite extends Suite with TestSuite with Informing with Notifying with Alerting with Documenting {
/**
* Register a test with the given name and function
* @param testName the name of the test
* @param testFun the test function to execute
*/
protected def test(testName: String)(testFun: => Any): Unit
/**
* Register a test to be ignored
* @param testName the name of the ignored test
* @param testFun the test function (will not be executed)
*/
protected def ignore(testName: String)(testFun: => Any): Unit
}
/**
* Asynchronous version returning Future[Assertion]
*/
abstract class AsyncFunSuite extends AsyncTestSuite with TestSuite {
protected def test(testName: String)(testFun: => Future[compatible.Assertion]): Unit
protected def ignore(testName: String)(testFun: => Future[compatible.Assertion]): Unit
}Usage Example:
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
class MathUtilsSpec extends AnyFunSuite with Matchers {
test("addition should work correctly") {
val result = MathUtils.add(2, 3)
result should equal(5)
}
test("division by zero should throw exception") {
assertThrows[ArithmeticException] {
MathUtils.divide(10, 0)
}
}
ignore("complex calculation - not implemented yet") {
// Test will be ignored
pending
}
}Flat, linear test style that encourages descriptive test names. Good for behavior-driven development and readable test reports.
/**
* Flat specification style with subject-behavior syntax
*/
abstract class AnyFlatSpec extends Suite with TestSuite {
/**
* Define behavior for a subject using "should", "must", "can"
* Usage: "Subject" should "behavior description" in { test }
*/
protected def behavior(description: String): Unit
/**
* Define ignored behavior
* Usage: "Subject" should "behavior" ignore { test }
*/
protected def ignore: Unit
}
abstract class AsyncFlatSpec extends AsyncTestSuite with TestSuite {
protected def behavior(description: String): Unit
}Usage Example:
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class StringUtilsSpec extends AnyFlatSpec with Matchers {
behavior of "StringUtils"
it should "reverse strings correctly" in {
StringUtils.reverse("hello") should equal("olleh")
StringUtils.reverse("") should equal("")
}
it should "capitalize first letter" in {
StringUtils.capitalize("hello") should equal("Hello")
StringUtils.capitalize("HELLO") should equal("HELLO")
}
"The reverse method" should "handle null input gracefully" in {
StringUtils.reverse(null) should be(null)
}
it should "work with unicode characters" ignore {
// Test not implemented yet
pending
}
}Specification style using nested contexts with "when", "should", "must", and "can". Excellent for complex behavior specification and acceptance testing.
/**
* Word-based specification style with nested contexts
*/
abstract class AnyWordSpec extends Suite with TestSuite {
/**
* Create nested specification contexts
* Usage: "Subject" when { "condition" should { "behavior" in { test } } }
*/
protected def when: WordSpecStringWrapper
protected def should: WordSpecStringWrapper
protected def must: WordSpecStringWrapper
protected def can: WordSpecStringWrapper
protected def which: WordSpecStringWrapper
}
abstract class AsyncWordSpec extends AsyncTestSuite with TestSuiteUsage Example:
import org.scalatest.wordspec.AnyWordSpec
import org.scalatest.matchers.should.Matchers
class BankAccountSpec extends AnyWordSpec with Matchers {
"A BankAccount" when {
"newly created" should {
"have zero balance" in {
val account = new BankAccount()
account.balance should equal(0.0)
}
"accept positive deposits" in {
val account = new BankAccount()
account.deposit(100.0)
account.balance should equal(100.0)
}
}
"with sufficient funds" should {
"allow withdrawals" in {
val account = new BankAccount()
account.deposit(100.0)
account.withdraw(50.0)
account.balance should equal(50.0)
}
}
"with insufficient funds" must {
"reject withdrawals" in {
val account = new BankAccount()
account.deposit(50.0)
assertThrows[InsufficientFundsException] {
account.withdraw(100.0)
}
}
}
}
}Free-form specification style with flexible nesting using dashes. Allows natural language test descriptions with arbitrary nesting levels.
/**
* Free-form specification style with dash-based nesting
*/
abstract class AnyFreeSpec extends Suite with TestSuite {
/**
* Create free-form nested specifications
* Usage: "description" - { test or nested specs }
*/
protected def -(text: String): FreeSpecStringWrapper
/**
* Ignore a specification
* Usage: "description" ignore { test }
*/
protected def ignore: Unit
}
abstract class AsyncFreeSpec extends AsyncTestSuite with TestSuiteUsage Example:
import org.scalatest.freespec.AnyFreeSpec
import org.scalatest.matchers.should.Matchers
class UserServiceSpec extends AnyFreeSpec with Matchers {
"UserService" - {
"when creating a new user" - {
"should validate email format" in {
val service = new UserService()
assertThrows[InvalidEmailException] {
service.createUser("john", "invalid-email")
}
}
"should generate unique ID" in {
val service = new UserService()
val user1 = service.createUser("john", "john@example.com")
val user2 = service.createUser("jane", "jane@example.com")
user1.id should not equal user2.id
}
"with duplicate email" - {
"should throw exception" in {
val service = new UserService()
service.createUser("john", "john@example.com")
assertThrows[DuplicateEmailException] {
service.createUser("jane", "john@example.com")
}
}
}
}
"when retrieving users" - {
"should return empty list initially" ignore {
// Test not implemented
pending
}
}
}
}RSpec-like specification style with "describe" and "it" blocks. Popular for behavior-driven development with natural language descriptions.
/**
* Function specification style similar to RSpec
*/
abstract class AnyFunSpec extends Suite with TestSuite {
/**
* Describe a component or behavior
* @param description what is being described
* @param fun nested specifications or tests
*/
protected def describe(description: String)(fun: => Unit): Unit
/**
* Specify individual behavior
* @param specText behavior description
* @param fun test implementation
*/
protected def it(specText: String)(fun: => Any): Unit
/**
* Ignore a specification
*/
protected def ignore(specText: String)(fun: => Any): Unit
}
abstract class AsyncFunSpec extends AsyncTestSuite with TestSuite {
protected def describe(description: String)(fun: => Unit): Unit
protected def it(specText: String)(fun: => Future[compatible.Assertion]): Unit
}Usage Example:
import org.scalatest.funspec.AnyFunSpec
import org.scalatest.matchers.should.Matchers
class CalculatorSpec extends AnyFunSpec with Matchers {
describe("Calculator") {
describe("when performing addition") {
it("should add positive numbers correctly") {
val calc = new Calculator()
calc.add(2, 3) should equal(5)
}
it("should handle negative numbers") {
val calc = new Calculator()
calc.add(-2, 3) should equal(1)
calc.add(-2, -3) should equal(-5)
}
}
describe("when performing division") {
it("should divide numbers correctly") {
val calc = new Calculator()
calc.divide(10, 2) should equal(5.0)
}
it("should handle division by zero") {
val calc = new Calculator()
assertThrows[ArithmeticException] {
calc.divide(10, 0)
}
}
ignore("should handle floating point precision") {
// Complex floating point test - not implemented yet
pending
}
}
}
}Gherkin-inspired BDD style with "Feature" and "Scenario" keywords. Ideal for acceptance testing and stakeholder communication.
/**
* Feature-driven specification style inspired by Gherkin/Cucumber
*/
abstract class AnyFeatureSpec extends Suite with TestSuite {
/**
* Define a feature
* @param description feature description
* @param fun scenarios for this feature
*/
protected def Feature(description: String)(fun: => Unit): Unit
/**
* Define a scenario within a feature
* @param description scenario description
* @param fun test implementation
*/
protected def Scenario(description: String)(fun: => Any): Unit
/**
* Ignore a scenario
*/
protected def ignore(description: String)(fun: => Any): Unit
}
abstract class AsyncFeatureSpec extends AsyncTestSuite with TestSuite {
protected def Feature(description: String)(fun: => Unit): Unit
protected def Scenario(description: String)(fun: => Future[compatible.Assertion]): Unit
}Usage Example:
import org.scalatest.featurespec.AnyFeatureSpec
import org.scalatest.matchers.should.Matchers
import org.scalatest.GivenWhenThen
class ShoppingCartSpec extends AnyFeatureSpec with Matchers with GivenWhenThen {
Feature("Shopping Cart Management") {
Scenario("Adding items to empty cart") {
Given("an empty shopping cart")
val cart = new ShoppingCart()
cart.items should be empty
When("I add an item")
val item = Item("Book", 29.99)
cart.addItem(item)
Then("the cart should contain the item")
cart.items should contain(item)
cart.total should equal(29.99)
}
Scenario("Removing items from cart") {
Given("a cart with items")
val cart = new ShoppingCart()
val book = Item("Book", 29.99)
val pen = Item("Pen", 2.50)
cart.addItem(book)
cart.addItem(pen)
When("I remove an item")
cart.removeItem(book)
Then("the cart should not contain that item")
cart.items should not contain book
cart.items should contain(pen)
cart.total should equal(2.50)
}
ignore("Applying discount codes") {
// Feature not yet implemented
pending
}
}
}Property-based testing style for defining properties that should hold for ranges of data. Integrates well with property testing libraries.
/**
* Property-based testing specification style
*/
abstract class AnyPropSpec extends Suite with TestSuite {
/**
* Define a property that should hold
* @param testName property description
* @param fun property test implementation
*/
protected def property(testName: String)(fun: => Any): Unit
/**
* Ignore a property
*/
protected def ignore(testName: String)(fun: => Any): Unit
}
abstract class AsyncPropSpec extends AsyncTestSuite with TestSuite {
protected def property(testName: String)(fun: => Future[compatible.Assertion]): Unit
}Usage Example:
import org.scalatest.propspec.AnyPropSpec
import org.scalatest.matchers.should.Matchers
class StringPropertiesSpec extends AnyPropSpec with Matchers {
property("string reverse is idempotent") {
forAll { (s: String) =>
StringUtils.reverse(StringUtils.reverse(s)) should equal(s)
}
}
property("string length is preserved by reverse") {
forAll { (s: String) =>
StringUtils.reverse(s).length should equal(s.length)
}
}
property("concatenation length is sum of individual lengths") {
forAll { (s1: String, s2: String) =>
(s1 + s2).length should equal(s1.length + s2.length)
}
}
ignore("complex unicode normalization properties") {
// Complex unicode property tests - not implemented
pending
}
}All test styles support fixture variants for managing test setup and teardown:
// Fixture variants available for all styles
abstract class FixtureAnyFunSuite extends fixture.TestSuite
abstract class FixtureAnyFlatSpec extends fixture.TestSuite
abstract class FixtureAnyWordSpec extends fixture.TestSuite
abstract class FixtureAnyFreeSpec extends fixture.TestSuite
abstract class FixtureAnyFunSpec extends fixture.TestSuite
abstract class FixtureAnyFeatureSpec extends fixture.TestSuite
abstract class FixtureAnyPropSpec extends fixture.TestSuite
// Async fixture variants
abstract class FixtureAsyncFunSuite extends fixture.AsyncTestSuite
abstract class FixtureAsyncFlatSpec extends fixture.AsyncTestSuite
// ... similar pattern for all async variantsFunSuite: Best for unit testing, simple test cases, teams familiar with xUnit frameworks
FlatSpec: Good for behavior specification, flat test structure, readable reports
WordSpec: Ideal for complex behavior specification, nested contexts, acceptance testing
FreeSpec: Perfect for natural language descriptions, flexible organization, documentation-like tests
FunSpec: Great for BDD, hierarchical organization, teams familiar with RSpec
FeatureSpec: Excellent for acceptance testing, stakeholder communication, Gherkin-style scenarios
PropSpec: Essential for property-based testing, mathematical properties, comprehensive test coverage
All styles can be mixed within the same test suite using Suites wrapper and support the same assertion and matcher capabilities.