ArchUnit with JUnit 5
ArchUnit is a Java library that allows you to define and enforce architectural rules, such as package dependencies, naming conventions, and layer boundaries, using unit tests.
This helps maintain a clean architecture and prevents unwanted dependencies from creeping into your codebase. It also catch architectural violations early in the development process.
Getting Started
Add Dependency
<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit5</artifactId>
<version>1.4.1</version>
<scope>test</scope>
</dependency>
Example of usage of Arch Unit
Ensuring your domain do not depends on external classes
This rule ensures that classes in your domain
package only depend on other domain classes or JDK classes, enforcing a clean domain model.
@AnalyzeClasses(
packages = "com.socgen.mycontrols",
importOptions = DoNotIncludeTests.class
)
class DomainArchTest {
@ArchTest
static final ArchRule domainShouldNotDependOnExternalClasses = classes()
.that().resideInAPackage("..domain..")
.should().onlyDependOnClassesThat().resideInAPackage(
"com.socgen.mycontrols.domain..",
"java.."
);
}
Ensuring a package only contains interfaces
This rule enforces that all classes in the domain.inbound
package are interfaces, which is useful for defining ports in a hexagonal architecture.
@AnalyzeClasses(
packages = "com.socgen.mycontrols",
importOptions = DoNotIncludeTests.class
)
class DomainArchTest {
@ArchTest
static final ArchRule inboundShouldOnlyBeInterfaces = classes()
.that().resideInAPackage("..domain.inbound..")
.should().beInterfaces();
}
Ensuring all classes are annotated under a package and have a name
This rule checks that all classes in the domain.usecases
package are annotated with @UseCase
and their names end with UseCase
.
@AnalyzeClasses(
packages = "com.socgen.mycontrols",
importOptions = DoNotIncludeTests.class
)
class DomainArchTest {
@ArchTest
static final ArchRule useCasesShouldBeAnnotatedAndShouldHaveUseCaseAtTheEndAsName = classes()
.that().resideInAPackage("..domain.usecases..")
.should().beAnnotatedWith(UseCase.class)
.andShould().haveSimpleNameEndingWith("UseCase");
}