or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-testing.mddeterministic-execution.mdevent-filtering.mdfsm-testing.mdindex.mdsynchronization.mdsynchronous-testing.mdtest-utilities.md

test-utilities.mddocs/

0

# Test Utilities and Helpers

1

2

Akka TestKit provides various utility classes, actors, and functions for common testing patterns including pre-built test actors, network utilities, serialization support, and configuration helpers.

3

4

## Capabilities

5

6

### Test Actors

7

8

Collection of pre-built actor implementations for common testing patterns and scenarios.

9

10

```scala { .api }

11

object TestActors {

12

/**

13

* Props for EchoActor - sends back received messages unmodified

14

* Useful for testing message routing and actor communication

15

*/

16

val echoActorProps: Props

17

18

/**

19

* Props for BlackholeActor - ignores all incoming messages

20

* Useful for testing scenarios where messages should be discarded

21

*/

22

val blackholeProps: Props

23

24

/**

25

* Props for ForwardActor - forwards all messages to specified ActorRef

26

* @param ref Target ActorRef to forward messages to

27

* @return Props for ForwardActor configured with target

28

*/

29

def forwardActorProps(ref: ActorRef): Props

30

}

31

32

/**

33

* Actor that echoes back all received messages

34

* Maintains original sender for proper request-response patterns

35

*/

36

class EchoActor extends Actor {

37

def receive: Receive = {

38

case message => sender() ! message

39

}

40

}

41

42

/**

43

* Actor that ignores all incoming messages

44

* Useful for dead-end routing and message sink scenarios

45

*/

46

class BlackholeActor extends Actor {

47

def receive: Receive = {

48

case _ => // Ignore all messages

49

}

50

}

51

52

/**

53

* Actor that forwards all messages to a specified target

54

* Maintains original sender for proper message forwarding

55

* @param ref Target ActorRef to forward messages to

56

*/

57

class ForwardActor(ref: ActorRef) extends Actor {

58

def receive: Receive = {

59

case message => ref.forward(message)

60

}

61

}

62

```

63

64

### Network Utilities

65

66

Utilities for network testing including port allocation and address management.

67

68

```scala { .api }

69

object SocketUtil {

70

/**

71

* Protocol types for network testing

72

*/

73

sealed trait Protocol

74

case object Tcp extends Protocol

75

case object Udp extends Protocol

76

case object Both extends Protocol

77

78

/**

79

* Constant for random loopback address allocation

80

*/

81

val RANDOM_LOOPBACK_ADDRESS = "RANDOM_LOOPBACK_ADDRESS"

82

83

/**

84

* Get a temporary free local port

85

* @param udp Whether to get UDP port (default: TCP)

86

* @return Available port number

87

*/

88

def temporaryLocalPort(udp: Boolean = false): Int

89

90

/**

91

* Get a temporary free local port for specific protocol

92

* @param protocol Protocol type (Tcp, Udp, or Both)

93

* @return Available port number that's free for the specified protocol

94

*/

95

def temporaryLocalPort(protocol: Protocol): Int

96

97

/**

98

* Get a temporary server address with free port

99

* @param address Hostname or IP address (use RANDOM_LOOPBACK_ADDRESS for random)

100

* @param udp Whether to get UDP address (default: TCP)

101

* @return InetSocketAddress with free port

102

*/

103

def temporaryServerAddress(address: String = "localhost", udp: Boolean = false): InetSocketAddress

104

105

/**

106

* Get hostname and port for temporary server

107

* @param interface Network interface name

108

* @return Tuple of (hostname, port)

109

*/

110

def temporaryServerHostnameAndPort(interface: String = "localhost"): (String, Int)

111

112

/**

113

* Get multiple temporary server addresses

114

* @param numberOfAddresses Number of addresses to generate

115

* @param hostname Hostname for all addresses

116

* @param udp Whether to get UDP addresses (default: TCP)

117

* @return IndexedSeq of InetSocketAddress instances with free ports

118

*/

119

def temporaryServerAddresses(numberOfAddresses: Int, hostname: String = "localhost",

120

udp: Boolean = false): immutable.IndexedSeq[InetSocketAddress]

121

122

/**

123

* Get server address that is not bound to any service

124

* @param address Hostname or IP address

125

* @return InetSocketAddress with available port

126

*/

127

def notBoundServerAddress(address: String = "localhost"): InetSocketAddress

128

129

/**

130

* Get server address that is not bound to any service (parameterless version)

131

* @return InetSocketAddress with localhost and available port

132

*/

133

def notBoundServerAddress(): InetSocketAddress

134

135

/**

136

* Get temporary UDP IPv6 port for specific network interface

137

* @param iface Network interface to bind to

138

* @return Available IPv6 UDP port number

139

*/

140

def temporaryUdpIpv6Port(iface: NetworkInterface): Int

141

}

142

```

143

144

### Test Exception

145

146

Predefined exception class for testing without stack trace overhead.

147

148

```scala { .api }

149

/**

150

* Predefined exception for testing scenarios

151

* Extends NoStackTrace to avoid stack trace generation overhead in tests

152

* @param message Exception message

153

*/

154

case class TestException(message: String) extends RuntimeException(message) with NoStackTrace

155

156

/**

157

* Companion object for TestException

158

*/

159

object TestException {

160

/**

161

* Create TestException with default message

162

* @return TestException with "test" message

163

*/

164

def apply(): TestException = TestException("test")

165

}

166

```

167

168

### Serialization Support

169

170

Utilities for testing serialization scenarios with Java serialization.

171

172

```scala { .api }

173

/**

174

* Java serialization support for ad-hoc test messages

175

* Useful when testing serialization without defining custom serializers

176

* @param system Extended actor system for serializer integration

177

*/

178

class TestJavaSerializer(val system: ExtendedActorSystem) extends BaseSerializer {

179

/**

180

* Serializer identifier for Akka serialization system

181

*/

182

def identifier: Int = 42

183

184

/**

185

* Serialize object to byte array using Java serialization

186

* @param o Object to serialize

187

* @return Serialized byte array

188

*/

189

def toBinary(o: AnyRef): Array[Byte]

190

191

/**

192

* Deserialize byte array to object using Java serialization

193

* @param bytes Serialized byte array

194

* @param clazz Optional class hint for deserialization

195

* @return Deserialized object

196

*/

197

def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef

198

199

/**

200

* Include manifest information for deserialization

201

*/

202

def includeManifest: Boolean = false

203

}

204

205

/**

206

* Marker trait for test messages that should use Java serialization

207

* Mix into test message classes to enable automatic Java serialization

208

*/

209

trait JavaSerializable extends Serializable {

210

// Marker trait - no additional methods

211

}

212

```

213

214

### Configuration and Extensions

215

216

TestKit configuration settings and extension utilities.

217

218

```scala { .api }

219

/**

220

* TestKit configuration settings

221

* @param config Configuration object with test settings

222

*/

223

class TestKitSettings(config: Config) {

224

/**

225

* Time scaling factor for tests - multiplies all timeouts

226

* Useful for running tests on slower systems

227

*/

228

val TestTimeFactor: Double

229

230

/**

231

* Default timeout for single message expectations

232

*/

233

val SingleExpectDefaultTimeout: FiniteDuration

234

235

/**

236

* Default timeout for expectNoMessage operations

237

*/

238

val ExpectNoMessageDefaultTimeout: FiniteDuration

239

240

/**

241

* Grace period for event filters to complete

242

*/

243

val TestEventFilterLeeway: FiniteDuration

244

245

/**

246

* Default Akka timeout for various operations

247

*/

248

val DefaultTimeout: Timeout

249

}

250

251

/**

252

* Extension for accessing TestKit settings

253

*/

254

object TestKitExtension extends ExtensionId[TestKitSettings] with ExtensionIdProvider {

255

/**

256

* Get TestKit settings for actor system

257

* @param system ActorSystem to get settings for

258

* @return TestKitSettings instance

259

*/

260

def get(system: ActorSystem): TestKitSettings

261

262

def lookup: TestKitExtension.type = TestKitExtension

263

264

def createExtension(system: ExtendedActorSystem): TestKitSettings =

265

new TestKitSettings(system.settings.config)

266

}

267

```

268

269

### Utility Functions

270

271

Miscellaneous utility functions for TestKit operations.

272

273

```scala { .api }

274

/**

275

* Utility functions for TestKit operations

276

*/

277

object TestKitUtils {

278

// Various internal utility functions for TestKit implementation

279

// Includes timing calculations, message queue management, etc.

280

}

281

```

282

283

### Implicit Traits

284

285

Commonly used traits that provide implicit values for testing convenience.

286

287

```scala { .api }

288

/**

289

* Automatically provides testActor as implicit sender

290

* Mix into test classes to avoid explicitly specifying sender

291

*/

292

trait ImplicitSender extends TestKitBase {

293

/**

294

* Implicit sender reference - uses testActor

295

*/

296

implicit def self: ActorRef = testActor

297

}

298

299

/**

300

* Provides default timeout from TestKit settings

301

* Mix into test classes for consistent timeout behavior

302

*/

303

trait DefaultTimeout extends TestKitBase {

304

/**

305

* Implicit timeout from TestKit configuration

306

*/

307

implicit val timeout: Timeout = testKitSettings.DefaultTimeout

308

}

309

```

310

311

### Time Dilation Support

312

313

Support for scaling time in test scenarios.

314

315

```scala { .api }

316

/**

317

* Implicit class for time dilation in tests

318

* Allows scaling of durations based on test time factor

319

* @param duration Original duration to scale

320

*/

321

implicit class TestDuration(val duration: FiniteDuration) extends AnyVal {

322

/**

323

* Scale duration by test time factor

324

* @param system Implicit ActorSystem for accessing time factor

325

* @return Scaled duration based on TestTimeFactor configuration

326

*/

327

def dilated(implicit system: ActorSystem): FiniteDuration =

328

Duration.fromNanos((duration.toNanos * TestKitExtension(system).TestTimeFactor + 0.5).toLong)

329

}

330

```

331

332

**Usage Examples:**

333

334

```scala

335

import akka.actor.{Actor, ActorSystem, Props}

336

import akka.testkit.{TestKit, TestActors, SocketUtil, TestException}

337

import java.net.InetSocketAddress

338

339

class TestUtilitiesExample extends TestKit(ActorSystem("test")) {

340

341

"TestActors" should {

342

"provide EchoActor for message echoing" in {

343

val echo = system.actorOf(TestActors.echoActorProps)

344

345

echo ! "hello"

346

expectMsg("hello")

347

348

echo ! 42

349

expectMsg(42)

350

351

echo ! List(1, 2, 3)

352

expectMsg(List(1, 2, 3))

353

}

354

355

"provide BlackholeActor for message ignoring" in {

356

val blackhole = system.actorOf(TestActors.blackholeProps)

357

358

// Messages are ignored - no response expected

359

blackhole ! "message1"

360

blackhole ! "message2"

361

blackhole ! "message3"

362

363

expectNoMessage(100.millis)

364

}

365

366

"provide ForwardActor for message forwarding" in {

367

val probe = TestProbe()

368

val forwarder = system.actorOf(TestActors.forwardActorProps(probe.ref))

369

370

forwarder ! "forwarded-message"

371

probe.expectMsg("forwarded-message")

372

373

// Original sender is maintained

374

probe.reply("response")

375

expectMsg("response")

376

}

377

}

378

379

"SocketUtil" should {

380

"provide free ports for network testing" in {

381

// Get free TCP port

382

val tcpPort = SocketUtil.temporaryLocalPort()

383

assert(tcpPort > 0 && tcpPort < 65536)

384

385

// Get free UDP port

386

val udpPort = SocketUtil.temporaryLocalPort(udp = true)

387

assert(udpPort > 0 && udpPort < 65536)

388

389

// Get port free for both protocols

390

val bothPort = SocketUtil.temporaryLocalPort(SocketUtil.Both)

391

assert(bothPort > 0 && bothPort < 65536)

392

}

393

394

"provide server addresses with free ports" in {

395

val address = SocketUtil.temporaryServerAddress("localhost", udp = false)

396

assert(address.getHostName == "localhost")

397

assert(address.getPort > 0)

398

399

// Multiple addresses

400

val addresses = SocketUtil.temporaryServerAddresses(3, "127.0.0.1", udp = false)

401

assert(addresses.length == 3)

402

addresses.foreach { addr =>

403

assert(addr.getHostName == "127.0.0.1")

404

assert(addr.getPort > 0)

405

}

406

407

// All ports should be different

408

val ports = addresses.map(_.getPort).toSet

409

assert(ports.size == 3)

410

}

411

}

412

413

"TestException" should {

414

"provide exception without stack trace overhead" in {

415

val exception = TestException("Test error message")

416

417

assert(exception.getMessage == "Test error message")

418

assert(exception.isInstanceOf[NoStackTrace])

419

420

// Use in test scenarios

421

intercept[TestException] {

422

throw TestException("Expected test failure")

423

}

424

}

425

}

426

427

"ImplicitSender trait" should {

428

"provide automatic sender" in {

429

// When mixing in ImplicitSender, testActor is used as sender automatically

430

val echo = system.actorOf(TestActors.echoActorProps)

431

432

echo ! "test-message"

433

expectMsg("test-message")

434

435

// No need to specify sender explicitly

436

}

437

}

438

439

"Time dilation" should {

440

"scale timeouts based on configuration" in {

441

import scala.concurrent.duration._

442

443

// Original duration

444

val original = 1.second

445

446

// Dilated duration (scaled by TestTimeFactor)

447

val dilated = original.dilated

448

449

// Use dilated timeouts in tests

450

within(dilated) {

451

// Test operations that should complete within scaled time

452

Thread.sleep(500) // This would work even if TestTimeFactor > 1

453

}

454

}

455

}

456

}

457

```

458

459

### Advanced Testing Patterns

460

461

Complex testing scenarios using multiple utilities together.

462

463

```scala

464

class AdvancedUtilitiesExample extends TestKit(ActorSystem("test")) {

465

466

class NetworkActor(host: String, port: Int) extends Actor {

467

def receive = {

468

case "connect" =>

469

// Simulate network connection

470

sender() ! s"connected-to-$host:$port"

471

case "disconnect" =>

472

sender() ! "disconnected"

473

case msg =>

474

sender() ! s"sent-$msg-to-$host:$port"

475

}

476

}

477

478

"Combined utilities" should {

479

"support complex network testing scenarios" in {

480

// Get free port for test server

481

val serverPort = SocketUtil.temporaryLocalPort()

482

val serverAddress = SocketUtil.temporaryServerAddress("localhost", udp = false)

483

484

// Create network actor with test port

485

val networkActor = system.actorOf(Props(new NetworkActor("localhost", serverPort)))

486

487

// Create echo actor for response testing

488

val echo = system.actorOf(TestActors.echoActorProps)

489

490

// Test network connection

491

networkActor ! "connect"

492

expectMsg(s"connected-to-localhost:$serverPort")

493

494

// Test message forwarding through network

495

val forwarder = system.actorOf(TestActors.forwardActorProps(echo))

496

forwarder ! "network-message"

497

expectMsg("network-message")

498

}

499

500

"support error testing with custom exceptions" in {

501

val actor = system.actorOf(Props(new Actor {

502

def receive = {

503

case "fail" => throw TestException("Simulated failure")

504

case msg => sender() ! s"processed-$msg"

505

}

506

}))

507

508

// Normal operation

509

actor ! "normal"

510

expectMsg("processed-normal")

511

512

// Error scenario with TestException

513

EventFilter[TestException](message = "Simulated failure").intercept {

514

actor ! "fail"

515

}

516

}

517

}

518

}

519

```

520

521

### Configuration Usage

522

523

Examples of using TestKit configuration and extensions.

524

525

```scala

526

class ConfigurationUsageExample extends TestKit(ActorSystem("test")) {

527

528

"TestKit configuration" should {

529

"provide access to test settings" in {

530

val settings = TestKitExtension(system)

531

532

println(s"Test time factor: ${settings.TestTimeFactor}")

533

println(s"Default timeout: ${settings.DefaultTimeout}")

534

println(s"Single expect timeout: ${settings.SingleExpectDefaultTimeout}")

535

536

// Use settings in test logic

537

val scaledTimeout = (1.second.toNanos * settings.TestTimeFactor).nanos

538

within(scaledTimeout) {

539

// Perform time-sensitive test operations

540

}

541

}

542

543

"support custom configuration" in {

544

import com.typesafe.config.ConfigFactory

545

546

val customConfig = ConfigFactory.parseString("""

547

akka.test {

548

timefactor = 2.0

549

single-expect-default = 10s

550

default-timeout = 15s

551

}

552

""")

553

554

val customSystem = ActorSystem("custom-test", customConfig)

555

val customSettings = TestKitExtension(customSystem)

556

557

assert(customSettings.TestTimeFactor == 2.0)

558

assert(customSettings.SingleExpectDefaultTimeout == 10.seconds)

559

560

TestKit.shutdownActorSystem(customSystem)

561

}

562

}

563

}

564

```

565

566

### Best Practices

567

568

Guidelines for effective use of TestKit utilities.

569

570

```scala

571

// GOOD: Use appropriate test actors for different scenarios

572

val echo = system.actorOf(TestActors.echoActorProps) // For response testing

573

val blackhole = system.actorOf(TestActors.blackholeProps) // For fire-and-forget testing

574

val forwarder = system.actorOf(TestActors.forwardActorProps(probe.ref)) // For routing testing

575

576

// GOOD: Get free ports for network tests to avoid conflicts

577

val port = SocketUtil.temporaryLocalPort()

578

val server = startTestServer(port)

579

580

// GOOD: Use TestException for expected test failures

581

def simulateError(): Unit = throw TestException("Expected test error")

582

583

// GOOD: Scale timeouts appropriately

584

val timeout = 5.seconds.dilated // Scales with TestTimeFactor

585

586

// GOOD: Mix in helpful traits

587

class MyTest extends TestKit(ActorSystem("test")) with ImplicitSender with DefaultTimeout

588

589

// AVOID: Hardcoded ports that might conflict

590

// val server = startTestServer(8080) // BAD - might be in use

591

592

// AVOID: Using real exceptions for expected test failures

593

// throw new RuntimeException("test") // BAD - generates unnecessary stack traces

594

```