or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

actor-references.mdcore-testing.mddeterministic-execution.mdevent-filtering.mdindex.mdjava-api.mdtest-utilities.mdutilities-config.md

utilities-config.mddocs/

0

# Utility Classes and Configuration

1

2

Akka TestKit provides various utility classes for configuration management, networking, serialization, and timing that support the core testing functionality. These utilities help create comprehensive test environments and handle common testing scenarios.

3

4

## Configuration System

5

6

### TestKitExtension { .api }

7

8

```scala

9

object TestKitExtension extends ExtensionId[TestKitSettings] {

10

def get(system: ActorSystem): TestKitSettings

11

def get(system: ClassicActorSystemProvider): TestKitSettings

12

def createExtension(system: ExtendedActorSystem): TestKitSettings

13

}

14

```

15

16

Extension system for accessing TestKit configuration settings.

17

18

### TestKitSettings { .api }

19

20

```scala

21

class TestKitSettings(config: Config) {

22

val TestTimeFactor: Double

23

val SingleExpectDefaultTimeout: FiniteDuration

24

val TestEventFilterLeeway: FiniteDuration

25

val DefaultTimeout: Timeout

26

}

27

```

28

29

Configuration holder containing all TestKit-related settings loaded from configuration files.

30

31

### Usage Examples

32

33

#### Accessing TestKit Settings

34

35

```scala

36

import akka.testkit.{TestKitExtension, TestKitSettings}

37

38

class ConfigurationTest extends TestKit(ActorSystem("TestSystem")) with ImplicitSender {

39

40

val settings: TestKitSettings = TestKitExtension(system)

41

42

"TestKit settings" should {

43

"provide access to configuration values" in {

44

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

45

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

46

println(s"Event filter leeway: ${settings.TestEventFilterLeeway}")

47

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

48

49

// Use settings in tests

50

within(settings.SingleExpectDefaultTimeout) {

51

testActor ! "ping"

52

expectMsg("pong")

53

}

54

}

55

}

56

}

57

```

58

59

#### Custom Configuration

60

61

```scala

62

import com.typesafe.config.ConfigFactory

63

64

// Custom test configuration

65

val testConfig = ConfigFactory.parseString("""

66

akka {

67

test {

68

# Scale factor for test timeouts

69

timefactor = 2.0

70

71

# Default timeout for single message expectations

72

single-expect-default = 5s

73

74

# Leeway for EventFilter operations

75

filter-leeway = 3s

76

77

# Default timeout for operations requiring implicit Timeout

78

default-timeout = 10s

79

}

80

}

81

""")

82

83

val system = ActorSystem("CustomTestSystem", testConfig)

84

val settings = TestKitExtension(system)

85

86

// Settings reflect custom configuration

87

assert(settings.TestTimeFactor == 2.0)

88

assert(settings.SingleExpectDefaultTimeout == 5.seconds)

89

```

90

91

#### Time Factor Usage

92

93

```scala

94

class TimeFactorTest extends TestKit(ActorSystem("TestSystem")) with ImplicitSender {

95

96

"Time factor" should {

97

"scale test durations automatically" in {

98

val settings = TestKitExtension(system)

99

val baseTimeout = 1.second

100

101

// Manual scaling

102

val scaledTimeout = Duration.fromNanos(

103

(baseTimeout.toNanos * settings.TestTimeFactor).toLong

104

)

105

106

// Or use TestDuration implicit class

107

import akka.testkit.TestDuration._

108

val dilatedTimeout = baseTimeout.dilated

109

110

assert(scaledTimeout == dilatedTimeout)

111

112

// Use in actual test

113

within(dilatedTimeout) {

114

someSlowActor ! "slow-operation"

115

expectMsg("completed")

116

}

117

}

118

}

119

}

120

```

121

122

## Timing Utilities

123

124

### TestDuration Implicit Class { .api }

125

126

```scala

127

// In akka.testkit package object

128

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

129

def dilated(implicit system: ActorSystem): FiniteDuration

130

}

131

```

132

133

Provides automatic time scaling for test durations based on the configured time factor.

134

135

### Usage Examples

136

137

#### Duration Scaling

138

139

```scala

140

import akka.testkit.TestDuration._

141

import scala.concurrent.duration._

142

143

class DurationScalingTest extends TestKit(ActorSystem("TestSystem")) {

144

145

"Duration scaling" should {

146

"automatically adjust timeouts" in {

147

// Base durations

148

val shortTimeout = 100.millis

149

val mediumTimeout = 1.second

150

val longTimeout = 5.seconds

151

152

// Scaled versions (uses TestTimeFactor from config)

153

val scaledShort = shortTimeout.dilated

154

val scaledMedium = mediumTimeout.dilated

155

val scaledLong = longTimeout.dilated

156

157

println(s"Short: ${shortTimeout} -> ${scaledShort}")

158

println(s"Medium: ${mediumTimeout} -> ${scaledMedium}")

159

println(s"Long: ${longTimeout} -> ${scaledLong}")

160

161

// Use in tests

162

within(scaledMedium) {

163

slowActor ! "request"

164

expectMsg(scaledShort, "response")

165

}

166

}

167

}

168

}

169

```

170

171

#### Conditional Scaling

172

173

```scala

174

class ConditionalScalingTest extends TestKit(ActorSystem("TestSystem")) {

175

176

"Conditional scaling" should {

177

"scale only when needed" in {

178

val baseTimeout = 2.seconds

179

val settings = TestKitExtension(system)

180

181

// Only scale if time factor is not 1.0

182

val effectiveTimeout = if (settings.TestTimeFactor != 1.0) {

183

baseTimeout.dilated

184

} else {

185

baseTimeout

186

}

187

188

within(effectiveTimeout) {

189

testActor ! "message"

190

expectMsg("response")

191

}

192

}

193

}

194

}

195

```

196

197

## Network Utilities

198

199

### SocketUtil { .api }

200

201

```scala

202

object SocketUtil {

203

def temporaryLocalPort(udp: Boolean = false): Int

204

def temporaryLocalPort(protocol: Protocol): Int

205

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

206

def temporaryServerAddresses(numberOfAddresses: Int, hostname: String = "127.0.0.1", udp: Boolean = false): immutable.IndexedSeq[InetSocketAddress]

207

208

sealed trait Protocol

209

case object Tcp extends Protocol

210

case object Udp extends Protocol

211

case object Both extends Protocol

212

}

213

```

214

215

Utilities for obtaining temporary network ports and addresses for testing network-based actors and services.

216

217

### Usage Examples

218

219

#### Basic Port Allocation

220

221

```scala

222

import akka.testkit.SocketUtil

223

import java.net.InetSocketAddress

224

225

class NetworkTest extends TestKit(ActorSystem("TestSystem")) {

226

227

"SocketUtil" should {

228

"provide temporary ports for testing" in {

229

// Get temporary TCP port

230

val tcpPort = SocketUtil.temporaryLocalPort(udp = false)

231

println(s"TCP port: $tcpPort")

232

233

// Get temporary UDP port

234

val udpPort = SocketUtil.temporaryLocalPort(udp = true)

235

println(s"UDP port: $udpPort")

236

237

// Get port by protocol

238

val tcpPort2 = SocketUtil.temporaryLocalPort(SocketUtil.Tcp)

239

val udpPort2 = SocketUtil.temporaryLocalPort(SocketUtil.Udp)

240

241

// All ports should be different

242

assert(tcpPort != udpPort)

243

assert(tcpPort != tcpPort2)

244

assert(udpPort != udpPort2)

245

}

246

247

"provide temporary addresses" in {

248

// Get temporary server address

249

val address = SocketUtil.temporaryServerAddress()

250

println(s"Address: ${address.getHostString}:${address.getPort}")

251

252

// Custom hostname

253

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

254

assert(customAddress.getHostString == "localhost")

255

256

// Multiple addresses

257

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

258

assert(addresses.length == 3)

259

addresses.foreach(addr => println(s"Address: ${addr}"))

260

}

261

}

262

}

263

```

264

265

#### Testing Network Actors

266

267

```scala

268

import akka.actor.{Actor, Props}

269

import akka.io.{IO, Tcp}

270

import java.net.InetSocketAddress

271

272

class NetworkActor extends Actor {

273

import Tcp._

274

import context.system

275

276

def receive = {

277

case "bind" =>

278

val port = SocketUtil.temporaryLocalPort()

279

val address = new InetSocketAddress("localhost", port)

280

IO(Tcp) ! Bind(self, address)

281

282

case b @ Bound(localAddress) =>

283

sender() ! s"bound:${localAddress.getPort}"

284

285

case CommandFailed(cmd) =>

286

sender() ! s"failed:${cmd}"

287

}

288

}

289

290

class NetworkActorTest extends TestKit(ActorSystem("TestSystem")) with ImplicitSender {

291

292

"NetworkActor" should {

293

"bind to temporary port" in {

294

val actor = system.actorOf(Props[NetworkActor])

295

296

actor ! "bind"

297

298

// Expect successful binding with port number

299

val response = expectMsgPF(5.seconds) {

300

case msg: String if msg.startsWith("bound:") => msg

301

}

302

303

val port = response.split(":")(1).toInt

304

assert(port > 0)

305

println(s"Successfully bound to port: $port")

306

}

307

}

308

}

309

```

310

311

#### Multi-Node Testing Setup

312

313

```scala

314

class MultiNodeTest extends TestKit(ActorSystem("TestSystem")) {

315

316

"Multi-node setup" should {

317

"allocate unique ports for each node" in {

318

val nodeCount = 3

319

val ports = (1 to nodeCount).map(_ => SocketUtil.temporaryLocalPort())

320

321

// All ports should be unique

322

assert(ports.distinct.length == nodeCount)

323

324

// Create addresses for each node

325

val addresses = ports.map(port => new InetSocketAddress("127.0.0.1", port))

326

327

addresses.zipWithIndex.foreach { case (addr, index) =>

328

println(s"Node $index: ${addr}")

329

}

330

331

// Use addresses to configure cluster nodes or test network communication

332

// ...

333

}

334

}

335

}

336

```

337

338

## Serialization Utilities

339

340

### TestMessageSerializer { .api }

341

342

```scala

343

class TestMessageSerializer(system: ExtendedActorSystem) extends Serializer {

344

def identifier: Int

345

def includeManifest: Boolean

346

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

347

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

348

}

349

```

350

351

A serializer designed for test messages that uses Java serialization for simplicity.

352

353

### JavaSerializable { .api }

354

355

```scala

356

trait JavaSerializable extends Serializable

357

```

358

359

Marker trait indicating that a message should use Java serialization in test environments.

360

361

### Usage Examples

362

363

#### Testing Message Serialization

364

365

```scala

366

import akka.serialization.SerializationExtension

367

368

// Test message with JavaSerializable marker

369

case class TestMessage(data: String, count: Int) extends JavaSerializable

370

371

class SerializationTest extends TestKit(ActorSystem("TestSystem")) {

372

373

"Message serialization" should {

374

"serialize and deserialize test messages" in {

375

val serialization = SerializationExtension(system)

376

val originalMessage = TestMessage("test-data", 42)

377

378

// Serialize

379

val serializer = serialization.findSerializerFor(originalMessage)

380

val bytes = serializer.toBinary(originalMessage)

381

println(s"Serialized to ${bytes.length} bytes")

382

383

// Deserialize

384

val deserializedMessage = serializer.fromBinary(bytes, Some(originalMessage.getClass))

385

386

// Verify

387

assert(deserializedMessage == originalMessage)

388

println(s"Successfully round-tripped: $deserializedMessage")

389

}

390

}

391

}

392

```

393

394

#### Custom Test Serializer Configuration

395

396

```scala

397

// Configure custom serializer in test configuration

398

val testConfig = ConfigFactory.parseString("""

399

akka {

400

actor {

401

serializers {

402

test = "akka.testkit.TestMessageSerializer"

403

}

404

serialization-bindings {

405

"akka.testkit.JavaSerializable" = test

406

}

407

}

408

}

409

""")

410

411

class CustomSerializationTest extends TestKit(ActorSystem("TestSystem", testConfig)) {

412

413

"Custom serialization" should {

414

"use TestMessageSerializer for JavaSerializable messages" in {

415

val serialization = SerializationExtension(system)

416

val message = TestMessage("serialized", 123)

417

418

val serializer = serialization.findSerializerFor(message)

419

assert(serializer.isInstanceOf[TestMessageSerializer])

420

421

// Test serialization roundtrip

422

val bytes = serializer.toBinary(message)

423

val restored = serializer.fromBinary(bytes, Some(message.getClass))

424

assert(restored == message)

425

}

426

}

427

}

428

```

429

430

## Configuration Management

431

432

### Test Configuration Patterns

433

434

#### Environment-Specific Configuration

435

436

```scala

437

import com.typesafe.config.{Config, ConfigFactory}

438

439

object TestConfiguration {

440

441

def forEnvironment(env: String): Config = {

442

val baseConfig = ConfigFactory.load("application-test.conf")

443

val envConfig = ConfigFactory.load(s"application-test-$env.conf")

444

envConfig.withFallback(baseConfig)

445

}

446

447

def withCustomDispatcher(): Config = {

448

ConfigFactory.parseString("""

449

akka {

450

actor {

451

default-dispatcher {

452

type = akka.testkit.CallingThreadDispatcherConfigurator

453

}

454

}

455

}

456

""")

457

}

458

459

def withTestScheduler(): Config = {

460

ConfigFactory.parseString("""

461

akka {

462

scheduler {

463

implementation = akka.testkit.ExplicitlyTriggeredScheduler

464

}

465

}

466

""")

467

}

468

469

def deterministicTestConfig(): Config = {

470

withCustomDispatcher()

471

.withFallback(withTestScheduler())

472

.withFallback(ConfigFactory.load("application-test.conf"))

473

}

474

}

475

476

// Usage in tests

477

class ConfigurableTest extends TestKit(ActorSystem("TestSystem", TestConfiguration.deterministicTestConfig())) {

478

479

"Configurable test" should {

480

"use deterministic execution" in {

481

// Test runs with CallingThreadDispatcher and ExplicitlyTriggeredScheduler

482

val actor = system.actorOf(Props[MyActor])

483

actor ! "test"

484

expectMsg("response") // Deterministic execution

485

}

486

}

487

}

488

```

489

490

#### Dynamic Configuration

491

492

```scala

493

import scala.util.Random

494

495

class DynamicConfigurationTest {

496

497

def createTestSystem(customSettings: Map[String, Any] = Map.empty): ActorSystem = {

498

val baseConfig = Map(

499

"akka.test.timefactor" -> 1.0,

500

"akka.test.single-expect-default" -> "3s",

501

"akka.test.filter-leeway" -> "3s"

502

)

503

504

val finalSettings = baseConfig ++ customSettings

505

val configString = finalSettings.map {

506

case (key, value) => s"$key = $value"

507

}.mkString("\n")

508

509

val config = ConfigFactory.parseString(configString)

510

.withFallback(ConfigFactory.load("application-test.conf"))

511

512

ActorSystem(s"TestSystem-${Random.nextInt(1000)}", config)

513

}

514

515

@Test

516

def testWithCustomTimeout(): Unit = {

517

val system = createTestSystem(Map(

518

"akka.test.single-expect-default" -> "10s",

519

"akka.test.timefactor" -> 2.0

520

))

521

522

new TestKit(system) {

523

val settings = TestKitExtension(system)

524

assert(settings.SingleExpectDefaultTimeout == 10.seconds)

525

assert(settings.TestTimeFactor == 2.0)

526

527

TestKit.shutdownActorSystem(system)

528

}

529

}

530

}

531

```

532

533

## Best Practices

534

535

### Configuration Best Practices

536

537

1. **Separate test configuration**: Use dedicated test configuration files

538

2. **Environment-specific settings**: Create configurations for different test environments

539

3. **Use time factors**: Scale timeouts appropriately for different environments

540

4. **Document settings**: Comment configuration values and their purposes

541

542

```scala

543

// Good: Well-documented test configuration

544

akka {

545

test {

546

# Scale timeouts by 2x for slower CI environments

547

timefactor = 2.0

548

549

# Longer default timeout for integration tests

550

single-expect-default = 5s

551

552

# Allow more time for event filter operations

553

filter-leeway = 3s

554

}

555

556

# Use deterministic dispatcher for unit tests

557

actor.default-dispatcher.type = akka.testkit.CallingThreadDispatcherConfigurator

558

559

# Suppress expected log messages

560

loggers = ["akka.testkit.TestEventListener"]

561

loglevel = "WARNING"

562

log-dead-letters = off

563

}

564

```

565

566

### Network Testing Best Practices

567

568

1. **Use temporary ports**: Always use SocketUtil for port allocation

569

2. **Clean up resources**: Ensure network resources are released after tests

570

3. **Test port conflicts**: Verify that multiple test runs don't conflict

571

4. **Handle binding failures**: Account for port binding failures in tests

572

573

```scala

574

// Good: Proper network resource management

575

class NetworkResourceTest extends TestKit(ActorSystem("TestSystem")) with BeforeAndAfterEach {

576

577

var allocatedPorts: List[Int] = List.empty

578

579

override def beforeEach(): Unit = {

580

allocatedPorts = List.empty

581

}

582

583

override def afterEach(): Unit = {

584

// Log allocated ports for debugging

585

if (allocatedPorts.nonEmpty) {

586

println(s"Test used ports: ${allocatedPorts.mkString(", ")}")

587

}

588

}

589

590

def getTestPort(): Int = {

591

val port = SocketUtil.temporaryLocalPort()

592

allocatedPorts = port :: allocatedPorts

593

port

594

}

595

}

596

```

597

598

### Serialization Testing Best Practices

599

600

1. **Test serialization boundaries**: Verify messages crossing serialization boundaries

601

2. **Use JavaSerializable for tests**: Simplify test message serialization

602

3. **Test large messages**: Verify behavior with large serialized messages

603

4. **Measure serialization performance**: Monitor serialization overhead in tests

604

605

```scala

606

// Good: Comprehensive serialization testing

607

case class LargeTestMessage(data: Array[Byte]) extends JavaSerializable

608

609

class SerializationPerformanceTest extends TestKit(ActorSystem("TestSystem")) {

610

611

"Serialization performance" should {

612

"handle large messages efficiently" in {

613

val serialization = SerializationExtension(system)

614

val largeData = Array.fill(1024 * 1024)(0.toByte) // 1MB

615

val message = LargeTestMessage(largeData)

616

617

val startTime = System.nanoTime()

618

val serializer = serialization.findSerializerFor(message)

619

val bytes = serializer.toBinary(message)

620

val deserializedMessage = serializer.fromBinary(bytes, Some(message.getClass))

621

val endTime = System.nanoTime()

622

623

val durationMs = (endTime - startTime) / 1000000

624

println(s"Serialization roundtrip took ${durationMs}ms for ${bytes.length} bytes")

625

626

assert(deserializedMessage.asInstanceOf[LargeTestMessage].data.sameElements(largeData))

627

assert(durationMs < 1000) // Should complete within 1 second

628

}

629

}

630

}

631

```