or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# ArchUnit JUnit 5 Engine

1

2

ArchUnit JUnit 5 Engine provides seamless integration between ArchUnit architecture testing and JUnit 5 test suites. This engine enables automatic discovery and execution of ArchUnit architecture tests as part of the JUnit Platform, allowing architectural constraints to be validated during regular test execution with full IDE and build tool support.

3

4

## Package Information

5

6

- **Package Name**: com.tngtech.archunit:archunit-junit5-engine

7

- **Package Type**: Maven

8

- **Language**: Java

9

- **Installation**: Add to test dependencies in build file

10

11

### Gradle

12

```gradle

13

testImplementation 'com.tngtech.archunit:archunit-junit5-engine:1.4.1'

14

```

15

16

### Maven

17

```xml

18

<dependency>

19

<groupId>com.tngtech.archunit</groupId>

20

<artifactId>archunit-junit5-engine</artifactId>

21

<version>1.4.1</version>

22

<scope>test</scope>

23

</dependency>

24

```

25

26

## Core Imports

27

28

```java

29

import com.tngtech.archunit.junit.AnalyzeClasses;

30

import com.tngtech.archunit.junit.ArchTest;

31

import com.tngtech.archunit.junit.ArchIgnore;

32

import com.tngtech.archunit.junit.ArchTag;

33

import com.tngtech.archunit.junit.ArchTests;

34

import com.tngtech.archunit.junit.CacheMode;

35

import com.tngtech.archunit.junit.LocationProvider;

36

import com.tngtech.archunit.junit.engine_api.FieldSelector;

37

import com.tngtech.archunit.junit.engine_api.FieldSource;

38

import com.tngtech.archunit.lang.ArchRule;

39

import com.tngtech.archunit.core.domain.JavaClasses;

40

import com.tngtech.archunit.core.importer.ImportOption;

41

import com.tngtech.archunit.core.importer.Location;

42

import java.util.Set;

43

import java.lang.reflect.Field;

44

```

45

46

## Basic Usage

47

48

```java

49

import com.tngtech.archunit.core.domain.JavaClasses;

50

import com.tngtech.archunit.junit.AnalyzeClasses;

51

import com.tngtech.archunit.junit.ArchTest;

52

import com.tngtech.archunit.lang.ArchRule;

53

54

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.*;

55

56

@AnalyzeClasses(packages = "com.myapp")

57

public class ArchitectureTest {

58

59

@ArchTest

60

public static final ArchRule layered_architecture =

61

layeredArchitecture()

62

.layer("Controller").definedBy("..controller..")

63

.layer("Service").definedBy("..service..")

64

.layer("Repository").definedBy("..repository..")

65

.whereLayer("Controller").mayNotBeAccessedByAnyLayer()

66

.whereLayer("Service").mayOnlyBeAccessedByLayers("Controller")

67

.whereLayer("Repository").mayOnlyBeAccessedByLayers("Service");

68

69

@ArchTest

70

public void services_should_only_be_accessed_by_controllers(JavaClasses classes) {

71

classes().that().resideInAPackage("..service..")

72

.should().onlyBeAccessed().byAnyPackage("..controller..", "..service..")

73

.check(classes);

74

}

75

}

76

```

77

78

## Architecture

79

80

The ArchUnit JUnit 5 Engine is built around several key components:

81

82

- **Test Engine**: Core JUnit Platform integration via `ArchUnitTestEngine` registered as 'archunit' engine

83

- **Test Discovery**: Automatic scanning for `@AnalyzeClasses` annotated classes containing `@ArchTest` fields/methods

84

- **Test Execution**: Executes ArchUnit rules against imported Java classes with comprehensive error reporting

85

- **Descriptor Hierarchy**: Organizes tests into hierarchical structure (Engine → Class → Field/Method descriptors)

86

- **Caching System**: Optimizes performance by caching imported Java classes across test executions

87

- **Filtering Support**: Supports JUnit Platform test filtering and custom ArchUnit property-based filtering

88

89

## Capabilities

90

91

### Test Discovery and Selectors

92

93

Provides JUnit Platform discovery selectors for programmatic test selection beyond standard class/method selection.

94

95

```java { .api }

96

/**

97

* Selector for ArchUnit test fields, enables programmatic discovery of specific @ArchTest fields

98

*/

99

public final class FieldSelector implements DiscoverySelector {

100

/**

101

* Select a field by class name and field name

102

* @param className - Fully qualified class name containing the field

103

* @param fieldName - Name of the @ArchTest field to select

104

* @return FieldSelector for the specified field

105

*/

106

public static FieldSelector selectField(String className, String fieldName);

107

108

/**

109

* Select a field by class and field name

110

* @param javaClass - Class containing the field

111

* @param fieldName - Name of the @ArchTest field to select

112

* @return FieldSelector for the specified field

113

*/

114

public static FieldSelector selectField(Class<?> javaClass, String fieldName);

115

116

/**

117

* Select a field by class and field instance

118

* @param javaClass - Class containing the field

119

* @param field - The @ArchTest field to select

120

* @return FieldSelector for the specified field

121

*/

122

public static FieldSelector selectField(Class<?> javaClass, Field field);

123

124

/** Get the Java class containing the selected field */

125

@Internal

126

public Class<?> getJavaClass();

127

128

/** Get the selected Java field */

129

@Internal

130

public Field getJavaField();

131

}

132

```

133

134

### Test Source Information

135

136

Provides detailed source information for ArchUnit test fields enabling IDE navigation and reporting.

137

138

```java { .api }

139

/**

140

* Test source implementation for ArchUnit test fields

141

*/

142

@PublicAPI(usage = ACCESS)

143

public final class FieldSource implements TestSource {

144

/**

145

* Create FieldSource from Field instance - internal use only

146

* @param field - The field to create source for

147

* @return FieldSource instance

148

*/

149

@Internal

150

static FieldSource from(Field field);

151

152

/** Get the fully qualified class name containing the field */

153

@PublicAPI(usage = ACCESS)

154

public String getClassName();

155

156

/** Get the Java class containing the field */

157

@PublicAPI(usage = ACCESS)

158

public Class<?> getJavaClass();

159

160

/** Get the field name */

161

@PublicAPI(usage = ACCESS)

162

public String getFieldName();

163

}

164

```

165

166

### Test Engine Registration

167

168

The engine automatically registers with JUnit Platform through service provider interface.

169

170

**Service Registration:**

171

- **File**: `META-INF/services/org.junit.platform.engine.TestEngine`

172

- **Implementation**: `com.tngtech.archunit.junit.internal.ArchUnitTestEngine`

173

- **Engine ID**: `"archunit"`

174

175

### Required Annotations

176

177

Tests must use these annotations from the core ArchUnit library:

178

179

```java { .api }

180

/**

181

* Specifies which packages/locations should be scanned when running JUnit 5 tests

182

*/

183

@Testable

184

@Target({TYPE})

185

@Retention(RUNTIME)

186

@PublicAPI(usage = ACCESS)

187

public @interface AnalyzeClasses {

188

/** Packages to look for within the classpath/modulepath */

189

String[] packages() default {};

190

191

/** Classes that specify packages to look for */

192

Class<?>[] packagesOf() default {};

193

194

/** Implementations of LocationProvider for custom class sources */

195

Class<? extends LocationProvider>[] locations() default {};

196

197

/** Whether to look for classes on the whole classpath */

198

boolean wholeClasspath() default false;

199

200

/** Types of ImportOption to use for filtering the class import */

201

Class<? extends ImportOption>[] importOptions() default {};

202

203

/** Controls if JavaClasses should be cached by location */

204

CacheMode cacheMode() default CacheMode.FOREVER;

205

}

206

207

/**

208

* Marks ArchUnit tests to be executed by the test infrastructure

209

*/

210

@Testable

211

@Target({FIELD, METHOD})

212

@Retention(RUNTIME)

213

public @interface ArchTest {

214

}

215

216

/**

217

* Marks rules to be ignored by the test support

218

*/

219

@Target({TYPE, FIELD, METHOD})

220

@Retention(RUNTIME)

221

public @interface ArchIgnore {

222

/** Why the test is ignored */

223

String reason() default "";

224

}

225

226

/**

227

* Repeatable annotation for tagging ArchTest fields/methods/classes

228

*/

229

@Inherited

230

@Documented

231

@Retention(RUNTIME)

232

@PublicAPI(usage = ACCESS)

233

@Repeatable(ArchTags.class)

234

@Target({TYPE, METHOD, FIELD})

235

public @interface ArchTag {

236

/** The actual tag value - must adhere to JUnit Platform tag syntax rules */

237

String value();

238

}

239

```

240

241

### Integration with ArchUnit Core

242

243

The engine integrates with core ArchUnit types and functionality:

244

245

```java { .api }

246

/**

247

* Collections of ArchUnit test rules for inclusion in test classes

248

*/

249

@PublicAPI(usage = ACCESS)

250

public final class ArchTests {

251

/**

252

* @param definitionLocation The class whose @ArchTest members should be included in this test

253

* @return the ArchTests of the supplied class

254

*/

255

@PublicAPI(usage = ACCESS)

256

public static ArchTests in(Class<?> definitionLocation);

257

}

258

259

/**

260

* Allows custom implementation to supply Locations to be imported by the JUnit test infrastructure

261

*/

262

@PublicAPI(usage = INHERITANCE)

263

public interface LocationProvider {

264

/**

265

* Returns locations to be imported for the current test run

266

* @param testClass The class object of the test currently executed

267

* @return The locations to import

268

*/

269

Set<Location> get(Class<?> testClass);

270

}

271

272

/**

273

* Determines how the JUnit test support caches classes

274

*/

275

@PublicAPI(usage = ACCESS)

276

public enum CacheMode {

277

/** Cache imported Java classes for current test class only */

278

@PublicAPI(usage = ACCESS)

279

PER_CLASS,

280

281

/** Cache imported Java classes by location using SoftReferences */

282

@PublicAPI(usage = ACCESS)

283

FOREVER

284

}

285

```

286

287

### Test Execution Patterns

288

289

**Field-based Tests (Recommended):**

290

```java

291

@AnalyzeClasses(packages = "com.example")

292

public class MyArchTest {

293

@ArchTest

294

public static final ArchRule rule = classes()

295

.that().resideInAPackage("..service..")

296

.should().notDependOn("..controller..");

297

}

298

```

299

300

**Method-based Tests:**

301

```java

302

@AnalyzeClasses(packages = "com.example")

303

public class MyArchTest {

304

@ArchTest

305

public void methodTest(JavaClasses classes) {

306

classes().that().resideInAPackage("..service..")

307

.should().notDependOn("..controller..")

308

.check(classes);

309

}

310

}

311

```

312

313

**Rule Libraries:**

314

```java

315

@AnalyzeClasses(packages = "com.example")

316

public class MyArchTest {

317

@ArchTest

318

public static final ArchTests rules = ArchTests.in(MyRuleLibrary.class);

319

}

320

```

321

322

### Test Filtering

323

324

**Property-based Filtering:**

325

```properties

326

# In archunit.properties or system property

327

junit.testFilter=specificRuleName,anotherRule

328

```

329

330

**JUnit Platform Filtering:**

331

Standard JUnit 5 filters work: class name filters, package filters, tags, etc.

332

333

## Error Handling

334

335

The engine provides comprehensive error reporting:

336

337

- **Initialization Errors**: Clear messages for missing `@AnalyzeClasses` annotations or invalid test method signatures

338

- **Rule Violations**: Detailed violation reports with class/method/field references and suggested fixes

339

- **Class Loading Issues**: Graceful handling of missing classes with informative error messages

340

- **Configuration Errors**: Validation of test method parameters (must accept single `JavaClasses` parameter)

341

342

## Performance Considerations

343

344

- **Class Cache**: Automatically caches imported `JavaClasses` to avoid repeated expensive import operations

345

- **Lazy Evaluation**: Test discovery and class analysis occur only when needed

346

- **Memory Management**: Cache is cleared per test class to prevent memory leaks

347

- **Concurrent Execution**: Thread-safe design supports parallel test execution

348

349

## Types

350

351

```java { .api }

352

// Key internal types (for understanding engine behavior)

353

interface CreatesChildren {

354

void createChildren(ElementResolver resolver);

355

}

356

357

// Test descriptor types extend JUnit Platform interfaces

358

abstract class AbstractArchUnitTestDescriptor extends AbstractTestDescriptor

359

implements Node<ArchUnitEngineExecutionContext>

360

361

class ArchUnitTestEngine extends HierarchicalTestEngine<ArchUnitEngineExecutionContext>

362

class ArchUnitEngineDescriptor extends EngineDescriptor

363

implements Node<ArchUnitEngineExecutionContext>

364

```