or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced.mdassertions.mdasync.mdfixtures.mdindex.mdmatchers.mdtest-styles.md

test-styles.mddocs/

0

# Test Suite Styles

1

2

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.

3

4

## Capabilities

5

6

### FunSuite - Function-Based Testing

7

8

xUnit-style testing with named test functions. Ideal for unit testing and teams familiar with JUnit/TestNG.

9

10

```scala { .api }

11

/**

12

* Function-based test suite similar to xUnit frameworks

13

*/

14

abstract class AnyFunSuite extends Suite with TestSuite with Informing with Notifying with Alerting with Documenting {

15

/**

16

* Register a test with the given name and function

17

* @param testName the name of the test

18

* @param testFun the test function to execute

19

*/

20

protected def test(testName: String)(testFun: => Any): Unit

21

22

/**

23

* Register a test to be ignored

24

* @param testName the name of the ignored test

25

* @param testFun the test function (will not be executed)

26

*/

27

protected def ignore(testName: String)(testFun: => Any): Unit

28

}

29

30

/**

31

* Asynchronous version returning Future[Assertion]

32

*/

33

abstract class AsyncFunSuite extends AsyncTestSuite with TestSuite {

34

protected def test(testName: String)(testFun: => Future[compatible.Assertion]): Unit

35

protected def ignore(testName: String)(testFun: => Future[compatible.Assertion]): Unit

36

}

37

```

38

39

**Usage Example:**

40

41

```scala

42

import org.scalatest.funsuite.AnyFunSuite

43

import org.scalatest.matchers.should.Matchers

44

45

class MathUtilsSpec extends AnyFunSuite with Matchers {

46

47

test("addition should work correctly") {

48

val result = MathUtils.add(2, 3)

49

result should equal(5)

50

}

51

52

test("division by zero should throw exception") {

53

assertThrows[ArithmeticException] {

54

MathUtils.divide(10, 0)

55

}

56

}

57

58

ignore("complex calculation - not implemented yet") {

59

// Test will be ignored

60

pending

61

}

62

}

63

```

64

65

### FlatSpec - Flat Specification Style

66

67

Flat, linear test style that encourages descriptive test names. Good for behavior-driven development and readable test reports.

68

69

```scala { .api }

70

/**

71

* Flat specification style with subject-behavior syntax

72

*/

73

abstract class AnyFlatSpec extends Suite with TestSuite {

74

/**

75

* Define behavior for a subject using "should", "must", "can"

76

* Usage: "Subject" should "behavior description" in { test }

77

*/

78

protected def behavior(description: String): Unit

79

80

/**

81

* Define ignored behavior

82

* Usage: "Subject" should "behavior" ignore { test }

83

*/

84

protected def ignore: Unit

85

}

86

87

abstract class AsyncFlatSpec extends AsyncTestSuite with TestSuite {

88

protected def behavior(description: String): Unit

89

}

90

```

91

92

**Usage Example:**

93

94

```scala

95

import org.scalatest.flatspec.AnyFlatSpec

96

import org.scalatest.matchers.should.Matchers

97

98

class StringUtilsSpec extends AnyFlatSpec with Matchers {

99

100

behavior of "StringUtils"

101

102

it should "reverse strings correctly" in {

103

StringUtils.reverse("hello") should equal("olleh")

104

StringUtils.reverse("") should equal("")

105

}

106

107

it should "capitalize first letter" in {

108

StringUtils.capitalize("hello") should equal("Hello")

109

StringUtils.capitalize("HELLO") should equal("HELLO")

110

}

111

112

"The reverse method" should "handle null input gracefully" in {

113

StringUtils.reverse(null) should be(null)

114

}

115

116

it should "work with unicode characters" ignore {

117

// Test not implemented yet

118

pending

119

}

120

}

121

```

122

123

### WordSpec - Word-Based Specification

124

125

Specification style using nested contexts with "when", "should", "must", and "can". Excellent for complex behavior specification and acceptance testing.

126

127

```scala { .api }

128

/**

129

* Word-based specification style with nested contexts

130

*/

131

abstract class AnyWordSpec extends Suite with TestSuite {

132

/**

133

* Create nested specification contexts

134

* Usage: "Subject" when { "condition" should { "behavior" in { test } } }

135

*/

136

protected def when: WordSpecStringWrapper

137

protected def should: WordSpecStringWrapper

138

protected def must: WordSpecStringWrapper

139

protected def can: WordSpecStringWrapper

140

protected def which: WordSpecStringWrapper

141

}

142

143

abstract class AsyncWordSpec extends AsyncTestSuite with TestSuite

144

```

145

146

**Usage Example:**

147

148

```scala

149

import org.scalatest.wordspec.AnyWordSpec

150

import org.scalatest.matchers.should.Matchers

151

152

class BankAccountSpec extends AnyWordSpec with Matchers {

153

154

"A BankAccount" when {

155

"newly created" should {

156

"have zero balance" in {

157

val account = new BankAccount()

158

account.balance should equal(0.0)

159

}

160

161

"accept positive deposits" in {

162

val account = new BankAccount()

163

account.deposit(100.0)

164

account.balance should equal(100.0)

165

}

166

}

167

168

"with sufficient funds" should {

169

"allow withdrawals" in {

170

val account = new BankAccount()

171

account.deposit(100.0)

172

account.withdraw(50.0)

173

account.balance should equal(50.0)

174

}

175

}

176

177

"with insufficient funds" must {

178

"reject withdrawals" in {

179

val account = new BankAccount()

180

account.deposit(50.0)

181

assertThrows[InsufficientFundsException] {

182

account.withdraw(100.0)

183

}

184

}

185

}

186

}

187

}

188

```

189

190

### FreeSpec - Free-Form Specification

191

192

Free-form specification style with flexible nesting using dashes. Allows natural language test descriptions with arbitrary nesting levels.

193

194

```scala { .api }

195

/**

196

* Free-form specification style with dash-based nesting

197

*/

198

abstract class AnyFreeSpec extends Suite with TestSuite {

199

/**

200

* Create free-form nested specifications

201

* Usage: "description" - { test or nested specs }

202

*/

203

protected def -(text: String): FreeSpecStringWrapper

204

205

/**

206

* Ignore a specification

207

* Usage: "description" ignore { test }

208

*/

209

protected def ignore: Unit

210

}

211

212

abstract class AsyncFreeSpec extends AsyncTestSuite with TestSuite

213

```

214

215

**Usage Example:**

216

217

```scala

218

import org.scalatest.freespec.AnyFreeSpec

219

import org.scalatest.matchers.should.Matchers

220

221

class UserServiceSpec extends AnyFreeSpec with Matchers {

222

223

"UserService" - {

224

"when creating a new user" - {

225

"should validate email format" in {

226

val service = new UserService()

227

assertThrows[InvalidEmailException] {

228

service.createUser("john", "invalid-email")

229

}

230

}

231

232

"should generate unique ID" in {

233

val service = new UserService()

234

val user1 = service.createUser("john", "john@example.com")

235

val user2 = service.createUser("jane", "jane@example.com")

236

user1.id should not equal user2.id

237

}

238

239

"with duplicate email" - {

240

"should throw exception" in {

241

val service = new UserService()

242

service.createUser("john", "john@example.com")

243

assertThrows[DuplicateEmailException] {

244

service.createUser("jane", "john@example.com")

245

}

246

}

247

}

248

}

249

250

"when retrieving users" - {

251

"should return empty list initially" ignore {

252

// Test not implemented

253

pending

254

}

255

}

256

}

257

}

258

```

259

260

### FunSpec - Function Specification Style

261

262

RSpec-like specification style with "describe" and "it" blocks. Popular for behavior-driven development with natural language descriptions.

263

264

```scala { .api }

265

/**

266

* Function specification style similar to RSpec

267

*/

268

abstract class AnyFunSpec extends Suite with TestSuite {

269

/**

270

* Describe a component or behavior

271

* @param description what is being described

272

* @param fun nested specifications or tests

273

*/

274

protected def describe(description: String)(fun: => Unit): Unit

275

276

/**

277

* Specify individual behavior

278

* @param specText behavior description

279

* @param fun test implementation

280

*/

281

protected def it(specText: String)(fun: => Any): Unit

282

283

/**

284

* Ignore a specification

285

*/

286

protected def ignore(specText: String)(fun: => Any): Unit

287

}

288

289

abstract class AsyncFunSpec extends AsyncTestSuite with TestSuite {

290

protected def describe(description: String)(fun: => Unit): Unit

291

protected def it(specText: String)(fun: => Future[compatible.Assertion]): Unit

292

}

293

```

294

295

**Usage Example:**

296

297

```scala

298

import org.scalatest.funspec.AnyFunSpec

299

import org.scalatest.matchers.should.Matchers

300

301

class CalculatorSpec extends AnyFunSpec with Matchers {

302

303

describe("Calculator") {

304

describe("when performing addition") {

305

it("should add positive numbers correctly") {

306

val calc = new Calculator()

307

calc.add(2, 3) should equal(5)

308

}

309

310

it("should handle negative numbers") {

311

val calc = new Calculator()

312

calc.add(-2, 3) should equal(1)

313

calc.add(-2, -3) should equal(-5)

314

}

315

}

316

317

describe("when performing division") {

318

it("should divide numbers correctly") {

319

val calc = new Calculator()

320

calc.divide(10, 2) should equal(5.0)

321

}

322

323

it("should handle division by zero") {

324

val calc = new Calculator()

325

assertThrows[ArithmeticException] {

326

calc.divide(10, 0)

327

}

328

}

329

330

ignore("should handle floating point precision") {

331

// Complex floating point test - not implemented yet

332

pending

333

}

334

}

335

}

336

}

337

```

338

339

### FeatureSpec - Feature Specification Style

340

341

Gherkin-inspired BDD style with "Feature" and "Scenario" keywords. Ideal for acceptance testing and stakeholder communication.

342

343

```scala { .api }

344

/**

345

* Feature-driven specification style inspired by Gherkin/Cucumber

346

*/

347

abstract class AnyFeatureSpec extends Suite with TestSuite {

348

/**

349

* Define a feature

350

* @param description feature description

351

* @param fun scenarios for this feature

352

*/

353

protected def Feature(description: String)(fun: => Unit): Unit

354

355

/**

356

* Define a scenario within a feature

357

* @param description scenario description

358

* @param fun test implementation

359

*/

360

protected def Scenario(description: String)(fun: => Any): Unit

361

362

/**

363

* Ignore a scenario

364

*/

365

protected def ignore(description: String)(fun: => Any): Unit

366

}

367

368

abstract class AsyncFeatureSpec extends AsyncTestSuite with TestSuite {

369

protected def Feature(description: String)(fun: => Unit): Unit

370

protected def Scenario(description: String)(fun: => Future[compatible.Assertion]): Unit

371

}

372

```

373

374

**Usage Example:**

375

376

```scala

377

import org.scalatest.featurespec.AnyFeatureSpec

378

import org.scalatest.matchers.should.Matchers

379

import org.scalatest.GivenWhenThen

380

381

class ShoppingCartSpec extends AnyFeatureSpec with Matchers with GivenWhenThen {

382

383

Feature("Shopping Cart Management") {

384

385

Scenario("Adding items to empty cart") {

386

Given("an empty shopping cart")

387

val cart = new ShoppingCart()

388

cart.items should be empty

389

390

When("I add an item")

391

val item = Item("Book", 29.99)

392

cart.addItem(item)

393

394

Then("the cart should contain the item")

395

cart.items should contain(item)

396

cart.total should equal(29.99)

397

}

398

399

Scenario("Removing items from cart") {

400

Given("a cart with items")

401

val cart = new ShoppingCart()

402

val book = Item("Book", 29.99)

403

val pen = Item("Pen", 2.50)

404

cart.addItem(book)

405

cart.addItem(pen)

406

407

When("I remove an item")

408

cart.removeItem(book)

409

410

Then("the cart should not contain that item")

411

cart.items should not contain book

412

cart.items should contain(pen)

413

cart.total should equal(2.50)

414

}

415

416

ignore("Applying discount codes") {

417

// Feature not yet implemented

418

pending

419

}

420

}

421

}

422

```

423

424

### PropSpec - Property-Based Testing Style

425

426

Property-based testing style for defining properties that should hold for ranges of data. Integrates well with property testing libraries.

427

428

```scala { .api }

429

/**

430

* Property-based testing specification style

431

*/

432

abstract class AnyPropSpec extends Suite with TestSuite {

433

/**

434

* Define a property that should hold

435

* @param testName property description

436

* @param fun property test implementation

437

*/

438

protected def property(testName: String)(fun: => Any): Unit

439

440

/**

441

* Ignore a property

442

*/

443

protected def ignore(testName: String)(fun: => Any): Unit

444

}

445

446

abstract class AsyncPropSpec extends AsyncTestSuite with TestSuite {

447

protected def property(testName: String)(fun: => Future[compatible.Assertion]): Unit

448

}

449

```

450

451

**Usage Example:**

452

453

```scala

454

import org.scalatest.propspec.AnyPropSpec

455

import org.scalatest.matchers.should.Matchers

456

457

class StringPropertiesSpec extends AnyPropSpec with Matchers {

458

459

property("string reverse is idempotent") {

460

forAll { (s: String) =>

461

StringUtils.reverse(StringUtils.reverse(s)) should equal(s)

462

}

463

}

464

465

property("string length is preserved by reverse") {

466

forAll { (s: String) =>

467

StringUtils.reverse(s).length should equal(s.length)

468

}

469

}

470

471

property("concatenation length is sum of individual lengths") {

472

forAll { (s1: String, s2: String) =>

473

(s1 + s2).length should equal(s1.length + s2.length)

474

}

475

}

476

477

ignore("complex unicode normalization properties") {

478

// Complex unicode property tests - not implemented

479

pending

480

}

481

}

482

```

483

484

## Fixture Support

485

486

All test styles support fixture variants for managing test setup and teardown:

487

488

### Fixture Variants

489

490

```scala { .api }

491

// Fixture variants available for all styles

492

abstract class FixtureAnyFunSuite extends fixture.TestSuite

493

abstract class FixtureAnyFlatSpec extends fixture.TestSuite

494

abstract class FixtureAnyWordSpec extends fixture.TestSuite

495

abstract class FixtureAnyFreeSpec extends fixture.TestSuite

496

abstract class FixtureAnyFunSpec extends fixture.TestSuite

497

abstract class FixtureAnyFeatureSpec extends fixture.TestSuite

498

abstract class FixtureAnyPropSpec extends fixture.TestSuite

499

500

// Async fixture variants

501

abstract class FixtureAsyncFunSuite extends fixture.AsyncTestSuite

502

abstract class FixtureAsyncFlatSpec extends fixture.AsyncTestSuite

503

// ... similar pattern for all async variants

504

```

505

506

### Choosing a Test Style

507

508

**FunSuite**: Best for unit testing, simple test cases, teams familiar with xUnit frameworks

509

**FlatSpec**: Good for behavior specification, flat test structure, readable reports

510

**WordSpec**: Ideal for complex behavior specification, nested contexts, acceptance testing

511

**FreeSpec**: Perfect for natural language descriptions, flexible organization, documentation-like tests

512

**FunSpec**: Great for BDD, hierarchical organization, teams familiar with RSpec

513

**FeatureSpec**: Excellent for acceptance testing, stakeholder communication, Gherkin-style scenarios

514

**PropSpec**: Essential for property-based testing, mathematical properties, comprehensive test coverage

515

516

All styles can be mixed within the same test suite using `Suites` wrapper and support the same assertion and matcher capabilities.