ArchUnit
BetA Java library for testing architectural rules as code
Metrics
What is it
ArchUnit is a Java library for testing architectural rules. It allows you to define architectural constraints as unit tests, ensuring that your code follows the architecture you’ve designed. You can enforce rules like “controllers should only call services,” “entities should not depend on infrastructure,” or “all classes in the ‘api’ package should be annotated with @RestController.”
My Opinion
ArchUnit is architecture as code. Instead of writing architectural guidelines in a Confluence document that no one reads, you encode them as tests that run on every build. When someone violates the architecture, the build fails. This is how you maintain architectural integrity over time without endless code review debates.
The “Tests as Documentation” Approach
The genius of ArchUnit is that it treats architecture as a testable artifact. Your architectural rules are:
- Version controlled alongside the code
- Automatically enforced on every commit
- Self-documenting through readable test names
- Part of the CI/CD pipeline
You don’t need to argue about architectural violations in code reviews—the test fails, the violation is rejected. No politics, no negotiation.
The Fluent API
ArchUnit’s API is elegant and readable:
@AnalyzeClasses(packages = "com.myapp")
public class ArchitectureTest {
@ArchTest
static final ArchRule controllers_should_only_call_services =
noClasses().that().resideInAPackage("..controller..")
.should().dependOnClassesThat().resideInAPackage("..repository..");
}
You’re essentially writing tests in English. The intent is clear, and the error messages are helpful when rules are violated.
The “Over-Engineering” Risk
The danger is getting carried away. You can define extremely complex architectural rules that become brittle and hard to maintain. Every refactoring becomes a game of Whac-A-Mole with ArchUnit tests.
The key is focusing on rules that actually matter: layer boundaries, circular dependency prevention, naming conventions. Don’t encode every opinion as a test.
The “Java-Only” Limitation
ArchUnit is Java-only. If you have a polyglot architecture with JavaScript, Python, or Go services, ArchUnit can only test the Java code. You’ll need different tools for different languages, which defeats the purpose of unified architectural testing.
For Spring applications, ArchUnit is perfect. For microservices in multiple languages, it’s a partial solution.
The “Startup” Overhead
If you’re a startup building an MVP, ArchUnit is overkill. You don’t need to enforce strict architectural boundaries when the architecture is changing every week. ArchUnit is for projects with stable architecture and teams large enough that not everyone knows every design decision.
Conclusion
ArchUnit is a powerful tool for maintaining architectural integrity in Java/Spring projects. The ability to encode architecture as tests prevents the gradual degradation of code structure over time. But use it judiciously—focus on the rules that actually matter, and don’t let it become a barrier to necessary evolution. For projects outside the Java ecosystem, you’ll need alternative approaches.