or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

boolean-assertions.mdcollection-assertions.mdequality-assertions.mdexception-testing.mdframework-integration.mdindex.mdtest-annotations.mdtest-utilities.mdtype-null-assertions.md

exception-testing.mddocs/

0

# Exception Testing

1

2

Exception assertion functions for testing error conditions with support for specific exception types and cause chains. These functions are essential for validating that code properly handles error cases and throws appropriate exceptions.

3

4

## Capabilities

5

6

### assertFails

7

8

Asserts that a code block throws any exception and returns the thrown exception.

9

10

```kotlin { .api }

11

/**

12

* Asserts that the given block fails by throwing an exception.

13

* @param block The code block that should throw an exception

14

* @return The thrown exception

15

* @throws AssertionError if the block completes without throwing

16

*/

17

fun assertFails(block: () -> Unit): Throwable

18

19

/**

20

* Asserts that the given block fails by throwing an exception.

21

* @param message Optional message to show if assertion fails

22

* @param block The code block that should throw an exception

23

* @return The thrown exception

24

* @throws AssertionError if the block completes without throwing

25

* @since Kotlin 1.1

26

*/

27

fun assertFails(message: String?, block: () -> Unit): Throwable

28

```

29

30

**Usage Examples:**

31

32

```kotlin

33

import kotlin.test.assertFails

34

import kotlin.test.assertEquals

35

36

@Test

37

fun testGeneralExceptionHandling() {

38

// Basic exception testing - any exception type

39

val exception = assertFails("Should throw when dividing by zero") {

40

val result = 10 / 0

41

}

42

assertTrue(exception is ArithmeticException)

43

44

// Testing API error responses

45

val apiException = assertFails {

46

apiClient.fetchUser("invalid-id")

47

}

48

assertContains(apiException.message ?: "", "invalid")

49

50

// Testing validation logic

51

assertFails("Should fail with invalid email") {

52

User.create(name = "John", email = "invalid-email")

53

}

54

55

// Testing concurrent operations

56

val concurrencyException = assertFails {

57

unsafeMap.putAll(generateLargeMap())

58

}

59

// Can examine the exception further

60

println("Caught exception: ${concurrencyException.javaClass.simpleName}")

61

}

62

```

63

64

### assertFailsWith (Reified)

65

66

Asserts that a code block throws a specific exception type using reified generics.

67

68

```kotlin { .api }

69

/**

70

* Asserts that the given block fails with a specific exception type.

71

* Uses reified generics for type-safe exception testing.

72

* @param message Optional message to show if assertion fails

73

* @param block The code block that should throw the exception

74

* @return The thrown exception cast to the specified type

75

* @throws AssertionError if block doesn't throw or throws wrong type

76

*/

77

inline fun <reified T : Throwable> assertFailsWith(

78

message: String? = null,

79

block: () -> Unit

80

): T

81

```

82

83

**Usage Examples:**

84

85

```kotlin

86

import kotlin.test.assertFailsWith

87

import kotlin.test.assertEquals

88

89

@Test

90

fun testSpecificExceptionTypes() {

91

// Test specific exception type with smart cast

92

val illegalArg = assertFailsWith<IllegalArgumentException> {

93

validateAge(-5)

94

}

95

assertEquals("Age cannot be negative", illegalArg.message)

96

97

// Test custom exceptions

98

val customException = assertFailsWith<UserNotFoundException>(

99

"Should throw UserNotFoundException for missing user"

100

) {

101

userService.getUser("nonexistent-id")

102

}

103

assertEquals("nonexistent-id", customException.userId)

104

105

// Test standard library exceptions

106

val indexException = assertFailsWith<IndexOutOfBoundsException> {

107

val list = listOf(1, 2, 3)

108

list[10] // Should throw

109

}

110

assertContains(indexException.message ?: "", "10")

111

112

// Test null pointer exceptions

113

val nullException = assertFailsWith<KotlinNullPointerException> {

114

val nullString: String? = null

115

nullString!!.length

116

}

117

118

// Test type cast exceptions

119

val castException = assertFailsWith<ClassCastException> {

120

val any: Any = "string"

121

any as Int

122

}

123

}

124

```

125

126

### assertFailsWith (KClass)

127

128

Asserts that a code block throws a specific exception type using KClass reflection.

129

130

```kotlin { .api }

131

/**

132

* Asserts that the given block fails with a specific exception class.

133

* Uses KClass for runtime type checking.

134

* @param exceptionClass The class of exception expected

135

* @param block The code block that should throw the exception

136

* @return The thrown exception cast to the specified type

137

* @throws AssertionError if block doesn't throw or throws wrong type

138

*/

139

fun <T : Throwable> assertFailsWith(

140

exceptionClass: KClass<T>,

141

block: () -> Unit

142

): T

143

144

/**

145

* Asserts that the given block fails with a specific exception class.

146

* @param exceptionClass The class of exception expected

147

* @param message Optional message to show if assertion fails

148

* @param block The code block that should throw the exception

149

* @return The thrown exception cast to the specified type

150

*/

151

fun <T : Throwable> assertFailsWith(

152

exceptionClass: KClass<T>,

153

message: String?,

154

block: () -> Unit

155

): T

156

```

157

158

**Usage Examples:**

159

160

```kotlin

161

import kotlin.test.assertFailsWith

162

import kotlin.reflect.KClass

163

164

@Test

165

fun testExceptionClassChecking() {

166

// Using KClass directly

167

val exception = assertFailsWith(IllegalStateException::class) {

168

stateMachine.performInvalidTransition()

169

}

170

assertContains(exception.message ?: "", "invalid transition")

171

172

// With custom message

173

val networkException = assertFailsWith(

174

NetworkException::class,

175

"Should throw NetworkException for connection timeout"

176

) {

177

networkClient.connectWithTimeout(timeout = 0)

178

}

179

assertEquals("Connection timeout", networkException.reason)

180

181

// Dynamic exception type testing

182

fun testDynamicException(expectedType: KClass<out Exception>) {

183

assertFailsWith(expectedType) {

184

riskyOperation()

185

}

186

}

187

188

testDynamicException(SecurityException::class)

189

testDynamicException(IllegalAccessException::class)

190

}

191

```

192

193

### Exception Hierarchy Testing

194

195

Test exception inheritance and exception cause chains.

196

197

**Usage Examples:**

198

199

```kotlin

200

import kotlin.test.assertFailsWith

201

import kotlin.test.assertIs

202

203

@Test

204

fun testExceptionHierarchy() {

205

// Test exception inheritance

206

val runtimeException = assertFailsWith<RuntimeException> {

207

// This throws IllegalArgumentException, which extends RuntimeException

208

validateInput("")

209

}

210

// Can check specific subtype

211

assertIs<IllegalArgumentException>(runtimeException)

212

213

// Test exception causes

214

val wrapperException = assertFailsWith<ServiceException> {

215

serviceLayer.performComplexOperation()

216

}

217

218

// Check the cause chain

219

val cause = wrapperException.cause

220

assertNotNull(cause, "Exception should have a cause")

221

assertIs<DatabaseException>(cause)

222

223

val rootCause = cause.cause

224

assertNotNull(rootCause, "Should have root cause")

225

assertIs<SQLException>(rootCause)

226

assertEquals("Connection timeout", rootCause.message)

227

}

228

229

@Test

230

fun testCustomExceptionProperties() {

231

// Test custom exception with additional properties

232

val validationException = assertFailsWith<ValidationException> {

233

validator.validate(invalidData)

234

}

235

236

assertEquals("field1", validationException.fieldName)

237

assertEquals("required", validationException.validationType)

238

assertTrue(validationException.errors.isNotEmpty())

239

240

// Test exception with error codes

241

val apiException = assertFailsWith<ApiException> {

242

apiClient.makeRequest("/invalid-endpoint")

243

}

244

245

assertEquals(404, apiException.statusCode)

246

assertEquals("NOT_FOUND", apiException.errorCode)

247

assertContains(apiException.details, "endpoint")

248

}

249

```

250

251

## Error Handling

252

253

Exception testing functions will throw an `AssertionError` when conditions fail:

254

255

- **assertFails**: Throws when the block completes without throwing any exception

256

- **assertFailsWith**: Throws when the block doesn't throw or throws the wrong exception type

257

258

Error messages provide clear information about the mismatch:

259

260

```kotlin

261

// This will throw: AssertionError: Expected an exception to be thrown, but was completed successfully.

262

assertFails {

263

val result = 2 + 2 // No exception thrown

264

}

265

266

// This will throw: AssertionError: Expected an exception of type IllegalArgumentException, actual was RuntimeException

267

assertFailsWith<IllegalArgumentException> {

268

throw RuntimeException("Wrong type")

269

}

270

```

271

272

## Best Practices

273

274

### Message Validation

275

Always validate exception messages to ensure meaningful error reporting:

276

277

```kotlin

278

val exception = assertFailsWith<ValidationException> {

279

validateEmail("invalid-email")

280

}

281

assertContains(exception.message ?: "", "email")

282

assertContains(exception.message ?: "", "format")

283

```

284

285

### Exception State Testing

286

Test that exceptions contain proper state information:

287

288

```kotlin

289

val businessException = assertFailsWith<InsufficientFundsException> {

290

account.withdraw(1000.0)

291

}

292

assertEquals(account.balance, businessException.availableBalance)

293

assertEquals(1000.0, businessException.requestedAmount)

294

```

295

296

### Cause Chain Validation

297

When testing wrapped exceptions, validate the entire cause chain:

298

299

```kotlin

300

val serviceException = assertFailsWith<ServiceException> {

301

userService.createUser(invalidUserData)

302

}

303

304

// Check immediate cause

305

val validationCause = assertIs<ValidationException>(serviceException.cause)

306

assertEquals("Invalid user data", validationCause.message)

307

308

// Check root cause

309

val fieldCause = assertIs<FieldValidationException>(validationCause.cause)

310

assertEquals("email", fieldCause.fieldName)

311

```