or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdconditional-execution.mdcore-testing.mddynamic-tests.mdextensions.mdindex.mdparallel-execution.mdparameterized-tests.md

dynamic-tests.mddocs/

0

# Dynamic Tests

1

2

Runtime test generation capabilities that allow creating tests programmatically during execution. Dynamic tests enable flexible test scenarios based on runtime data and conditions.

3

4

## Imports

5

6

```java

7

import org.junit.jupiter.api.*;

8

import java.util.stream.Stream;

9

import java.util.Collection;

10

import static org.junit.jupiter.api.Assertions.*;

11

import static org.junit.jupiter.api.DynamicTest.dynamicTest;

12

import static org.junit.jupiter.api.DynamicContainer.dynamicContainer;

13

```

14

15

## Capabilities

16

17

### Test Factory Annotation

18

19

Mark methods that generate dynamic tests at runtime.

20

21

```java { .api }

22

/**

23

* Marks a method as a factory for dynamic tests

24

* Method must return Stream, Collection, Iterable, or Iterator of DynamicNode

25

*/

26

@Target(ElementType.METHOD)

27

@Retention(RetentionPolicy.RUNTIME)

28

@interface TestFactory {

29

}

30

```

31

32

### Dynamic Test Creation

33

34

Create individual dynamic test instances.

35

36

```java { .api }

37

/**

38

* A dynamically generated test

39

*/

40

class DynamicTest extends DynamicNode {

41

/**

42

* Create a dynamic test with display name and executable

43

*/

44

static DynamicTest dynamicTest(String displayName, Executable executable);

45

46

/**

47

* Create a dynamic test with display name, URI, and executable

48

*/

49

static DynamicTest dynamicTest(String displayName, URI testSourceUri, Executable executable);

50

51

/**

52

* Create a stream of dynamic tests from input data

53

*/

54

static <T> Stream<DynamicTest> stream(Iterator<T> inputGenerator,

55

Function<? super T, String> displayNameGenerator,

56

ThrowingConsumer<? super T> testExecutor);

57

58

/**

59

* Create a stream of dynamic tests from input stream

60

*/

61

static <T> Stream<DynamicTest> stream(Stream<T> inputStream,

62

Function<? super T, String> displayNameGenerator,

63

ThrowingConsumer<? super T> testExecutor);

64

}

65

```

66

67

**Usage Examples:**

68

69

```java

70

class DynamicTestExample {

71

72

@TestFactory

73

Stream<DynamicTest> simpleTests() {

74

return Stream.of("apple", "banana", "cherry")

75

.map(fruit -> DynamicTest.dynamicTest(

76

"test " + fruit,

77

() -> {

78

assertNotNull(fruit);

79

assertTrue(fruit.length() > 3);

80

}

81

));

82

}

83

84

@TestFactory

85

Collection<DynamicTest> numbersTest() {

86

return Arrays.asList(

87

DynamicTest.dynamicTest("Test 1", () -> assertEquals(2, 1 + 1)),

88

DynamicTest.dynamicTest("Test 2", () -> assertEquals(4, 2 * 2)),

89

DynamicTest.dynamicTest("Test 3", () -> assertEquals(9, 3 * 3))

90

);

91

}

92

93

@TestFactory

94

Stream<DynamicTest> dataStreamTests() {

95

List<String> data = Arrays.asList("alpha", "beta", "gamma");

96

97

return DynamicTest.stream(

98

data.stream(),

99

name -> "Processing " + name,

100

value -> {

101

assertNotNull(value);

102

assertTrue(value.length() > 3);

103

assertFalse(value.isEmpty());

104

}

105

);

106

}

107

}

108

```

109

110

### Dynamic Container Creation

111

112

Group related dynamic tests in containers.

113

114

```java { .api }

115

/**

116

* A container for dynamic tests or other containers

117

*/

118

class DynamicContainer extends DynamicNode {

119

/**

120

* Create a dynamic container with display name and children

121

*/

122

static DynamicContainer dynamicContainer(String displayName, Stream<DynamicNode> children);

123

124

/**

125

* Create a dynamic container with display name, URI, and children

126

*/

127

static DynamicContainer dynamicContainer(String displayName, URI testSourceUri, Stream<DynamicNode> children);

128

129

/**

130

* Create a dynamic container with display name and iterable children

131

*/

132

static DynamicContainer dynamicContainer(String displayName, Iterable<DynamicNode> children);

133

134

/**

135

* Create a dynamic container with display name, URI, and iterable children

136

*/

137

static DynamicContainer dynamicContainer(String displayName, URI testSourceUri, Iterable<DynamicNode> children);

138

}

139

```

140

141

**Usage Examples:**

142

143

```java

144

class DynamicContainerExample {

145

146

@TestFactory

147

Stream<DynamicNode> nestedTests() {

148

return Stream.of(

149

DynamicContainer.dynamicContainer("String Tests", Stream.of(

150

DynamicTest.dynamicTest("Test empty string", () -> assertTrue("".isEmpty())),

151

DynamicTest.dynamicTest("Test non-empty string", () -> assertFalse("hello".isEmpty()))

152

)),

153

154

DynamicContainer.dynamicContainer("Number Tests", Stream.of(

155

DynamicTest.dynamicTest("Test positive", () -> assertTrue(5 > 0)),

156

DynamicTest.dynamicTest("Test negative", () -> assertTrue(-5 < 0))

157

))

158

);

159

}

160

161

@TestFactory

162

Stream<DynamicNode> hierarchicalTests() {

163

return Stream.of("Category A", "Category B")

164

.map(category -> DynamicContainer.dynamicContainer(

165

category,

166

IntStream.range(1, 4)

167

.mapToObj(i -> DynamicTest.dynamicTest(

168

category + " Test " + i,

169

() -> {

170

assertNotNull(category);

171

assertTrue(i > 0);

172

}

173

))

174

));

175

}

176

}

177

```

178

179

### Dynamic Node Base

180

181

Base class for all dynamic test elements.

182

183

```java { .api }

184

/**

185

* Base class for dynamic tests and containers

186

*/

187

abstract class DynamicNode {

188

/**

189

* Get display name

190

*/

191

String getDisplayName();

192

193

/**

194

* Get test source URI

195

*/

196

Optional<URI> getTestSourceUri();

197

}

198

```

199

200

### Named Interface

201

202

Interface for providing names to test components.

203

204

```java { .api }

205

/**

206

* Interface for named test components

207

*/

208

interface Named {

209

/**

210

* Get the name

211

*/

212

String getName();

213

214

/**

215

* Create Named instance with given name and payload

216

*/

217

static <T> Named<T> of(String name, T payload);

218

}

219

220

/**

221

* Named executable for dynamic test creation

222

*/

223

interface NamedExecutable extends Named {

224

/**

225

* Get the executable

226

*/

227

Executable getExecutable();

228

229

/**

230

* Create NamedExecutable with name and executable

231

*/

232

static NamedExecutable of(String name, Executable executable);

233

}

234

```

235

236

**Usage Examples:**

237

238

```java

239

class NamedTestExample {

240

241

@TestFactory

242

Stream<DynamicTest> namedTests() {

243

List<Named<String>> testData = Arrays.asList(

244

Named.of("First test", "alpha"),

245

Named.of("Second test", "beta"),

246

Named.of("Third test", "gamma")

247

);

248

249

return testData.stream()

250

.map(namedData -> DynamicTest.dynamicTest(

251

namedData.getName(),

252

() -> {

253

String value = namedData.getPayload();

254

assertNotNull(value);

255

assertTrue(value.length() > 3);

256

}

257

));

258

}

259

260

@TestFactory

261

Stream<DynamicTest> namedExecutableTests() {

262

List<NamedExecutable> executables = Arrays.asList(

263

NamedExecutable.of("Test addition", () -> assertEquals(4, 2 + 2)),

264

NamedExecutable.of("Test subtraction", () -> assertEquals(0, 2 - 2)),

265

NamedExecutable.of("Test multiplication", () -> assertEquals(4, 2 * 2))

266

);

267

268

return executables.stream()

269

.map(namedExec -> DynamicTest.dynamicTest(

270

namedExec.getName(),

271

namedExec.getExecutable()

272

));

273

}

274

}

275

```

276

277

### Complex Dynamic Test Scenarios

278

279

Advanced patterns for dynamic test generation.

280

281

**Database-driven Tests:**

282

283

```java

284

class DatabaseDrivenTests {

285

286

@TestFactory

287

Stream<DynamicTest> testAllUsers() {

288

UserRepository repository = new UserRepository();

289

290

return repository.findAll().stream()

291

.map(user -> DynamicTest.dynamicTest(

292

"Validate user: " + user.getUsername(),

293

() -> {

294

assertNotNull(user.getEmail());

295

assertTrue(user.getAge() >= 0);

296

assertFalse(user.getUsername().isEmpty());

297

}

298

));

299

}

300

301

@TestFactory

302

Stream<DynamicNode> testUsersByRole() {

303

UserRepository repository = new UserRepository();

304

Map<String, List<User>> usersByRole = repository.findAll().stream()

305

.collect(Collectors.groupingBy(User::getRole));

306

307

return usersByRole.entrySet().stream()

308

.map(entry -> DynamicContainer.dynamicContainer(

309

"Role: " + entry.getKey(),

310

entry.getValue().stream()

311

.map(user -> DynamicTest.dynamicTest(

312

"Test " + user.getUsername(),

313

() -> validateUserInRole(user, entry.getKey())

314

))

315

));

316

}

317

318

private void validateUserInRole(User user, String expectedRole) {

319

assertEquals(expectedRole, user.getRole());

320

assertNotNull(user.getPermissions());

321

assertFalse(user.getPermissions().isEmpty());

322

}

323

}

324

```

325

326

**Configuration-based Tests:**

327

328

```java

329

class ConfigurationBasedTests {

330

331

@TestFactory

332

Stream<DynamicTest> testConfigurations() throws IOException {

333

Properties configs = loadTestConfigurations();

334

335

return configs.entrySet().stream()

336

.map(entry -> DynamicTest.dynamicTest(

337

"Test config: " + entry.getKey(),

338

() -> {

339

String key = (String) entry.getKey();

340

String value = (String) entry.getValue();

341

342

assertNotNull(value, "Configuration value should not be null");

343

validateConfigurationValue(key, value);

344

}

345

));

346

}

347

348

@TestFactory

349

Stream<DynamicNode> testConfigurationGroups() throws IOException {

350

Map<String, Properties> configGroups = loadConfigurationGroups();

351

352

return configGroups.entrySet().stream()

353

.map(group -> DynamicContainer.dynamicContainer(

354

"Config Group: " + group.getKey(),

355

group.getValue().entrySet().stream()

356

.map(config -> DynamicTest.dynamicTest(

357

"Test " + config.getKey(),

358

() -> validateConfigurationValue(

359

(String) config.getKey(),

360

(String) config.getValue()

361

)

362

))

363

));

364

}

365

366

private Properties loadTestConfigurations() throws IOException {

367

Properties props = new Properties();

368

props.load(getClass().getResourceAsStream("/test-config.properties"));

369

return props;

370

}

371

372

private Map<String, Properties> loadConfigurationGroups() {

373

// Load different configuration groups

374

return Map.of(

375

"database", loadDatabaseConfigs(),

376

"security", loadSecurityConfigs(),

377

"performance", loadPerformanceConfigs()

378

);

379

}

380

381

private void validateConfigurationValue(String key, String value) {

382

switch (key) {

383

case "timeout":

384

assertTrue(Integer.parseInt(value) > 0);

385

break;

386

case "url":

387

assertTrue(value.startsWith("http"));

388

break;

389

default:

390

assertNotNull(value);

391

}

392

}

393

}

394

```