Common ArchUnit tooling for Java / Spring Boot projects.
Add this library to the classpath by adding the following maven dependency. Versions can be found here
<dependency>
<groupId>it.aboutbits</groupId>
<artifactId>archunit-toolbox</artifactId>
<version>x.x.x</version>
<scope>test</scope>
</dependency>This release will fail builds that passed on 1.2.0, on purpose. Nine rules were silently reporting success because they matched nothing; fixing them turns real violations into build failures for the first time. Expect two kinds:
- Revived rules surface real violations. Chiefly the two that were fully dead:
test_classes_should_be_in_the_same_package_as_their_production_codeandnested_test_classes_have_matching_production_method_name. Triage them with the opt-out stereotype described under Opting out before annotating classes one at a time. The stricter paths (getCodeUnits()reaching constructors and field initializers, exact security-test matching,SortMappingsreporting what it cannot read) surfaced nothing in a large codebase, so noise from those is unlikely. analyzed_packages_must_contain_classesis new and fails on an empty import. If the packages given to@AnalyzeClassesare mistyped or have moved, that is now a failure instead of 13 rules quietly passing.
Nothing else needs a migration: no rule fails over code your project does not have.
Implement one of the provided rule collections in your own architecture test.
@AnalyzeClasses(
packages = ArchitectureTest.PACKAGE
)
@NullMarked
@ArchIgnoreNoProductionCounterpart
class ArchitectureTest implements BaseArchRuleCollection {
static final String PACKAGE = "the.base.package.of.your.project";
}BaseArchRuleCollection holds the rules that apply to any Java project. CommonArchRuleCollection
adds rules for Spring MVC controllers and for SortMappings, so implement it only in a project that
has them.
The blacklists are mutable, so a project can drop an entry it disagrees with:
static {
BlacklistClassesArchRule.BLACKLISTED_CLASSES.remove("net.datafaker.Faker");
}The same applies to ArchRuleConfig.TEST_CLASS_SUFFIXES when a project introduces a new test type.
Every rule tolerates a selection that comes up empty, so a rule simply passes on a project it does
not apply to. Whether a project has records, controllers, @Store classes or @Nested test classes
is the project's business, not something this library requires.
That each rule can actually fail is guaranteed by a red test per rule in this repository, rather than by making your build fail over code you do not have. An empty selection says nothing about whether a rule's logic works.
One case is a real problem though, and analyzed_packages_must_contain_classes covers it: if the
packages given to @AnalyzeClasses are mistyped or have moved, nothing is imported and every other
rule would pass without looking at a single class. That fails, once, with a message naming the cause.
Two annotations exempt a class from a specific rule. Neither is meta-annotated with ArchUnit's
@ArchIgnore: the ArchUnit JUnit engine resolves meta-annotations, so that would skip every
@ArchTest on the annotated class and report success rather than exempting it from one rule.
| annotation | put it on | exempts from |
|---|---|---|
@ArchIgnoreNoProductionCounterpart |
a test class | needing a production class of the same name in the same package, and having its @Nested classes matched against production methods |
@ArchIgnoreGroupName |
a @Nested test class |
needing a production method of the same name, for a class that only groups tests |
Use @ArchIgnoreNoProductionCounterpart for a test named after the behaviour it describes rather than
after a production class.
Both are read as meta-annotations, so a project declares its intent once on its own stereotype instead of repeating the annotation on every class:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ArchIgnoreNoProductionCounterpart
public @interface BusinessTest {
}Annotating a single class directly still works — ArchUnit counts a direct annotation as meta-annotated.
The same applies to @Disabled and ArchUnit's @ArchIgnore, which these rules also honour: a
stereotype that carries either of them exempts every class using it. That matches how JUnit and the
ArchUnit engine themselves read those two annotations — a class whose tests do not run is not held to
naming rules — but it does mean a stereotype can exempt more than it appears to, so keep an eye on
what your own test annotations carry.
Architecture tests need neither: any class in a package named _architecture is exempt from the
production-counterpart rule, alongside the existing _support and _config exclusions. Use the
annotation for the one-off that lives elsewhere.
To use this library as a local development dependency, you can simply refer to the version BUILD-SNAPSHOT.
Check out this repository and run the maven goal install. This will build and install this library as version BUILD-SNAPSHOT into your local maven cache.
Note that you may have to tell your IDE to reload your main maven project each time you build the library.
To build and publish the chart, visit the GitHub Actions page of the repository and trigger the workflow "Release Package" manually.
About Bits is a company based in South Tyrol, Italy. You can find more information about us on our website.
For support, please contact info@aboutbits.it.
The MIT License (MIT). Please see the license file for more information.