How to validate architectural constraints in Java projects using ArchUnit
As projects grow, the architecture becomes more complex. Each project has standard rules that developers need to follow. If new colleagues join the project, they might violate the architectural constraints without even knowing about it. If everyone adds new code wherever they think it fits, the code base will become messy.
It leads to laborious code maintenance and opens doors to bugs. Of course, there might be a senior developer who had been working on the project for years. They review the new code periodically and let the others know if they should fix anything.
The problem is that this requires manual intervention, and sometimes humans don’t spot all the issues. The best way of protecting the software architecture from violations is to have an automated process.
In this article, I’ll showcase the ArchUnit framework that tackles such issues. You’ll see typical practical examples to understand how to integrate this tool into your projects.
Let’s dive into it!
ArchUnit serves for unit testing Java projects architecture. It validates the architectural constraints. Usually, an architect or a lead developer establishes the general patterns. They write the rules in human-readable unit tests that can be evaluated with any unit testing tool like JUnit.
When someone breaks the rules, the tests will fail. Developers will see information about the issue. It ensures that the codebase stays intact and everyone follows the guidelines.
This art of testing is especially beneficial for new joiners to understand the project structure.
I assume you already have a Java project for testing, for example, a SpringBoot project.
First, add the ArchUnit maven dependency to your
Now let’s take a look into some common use cases.
Create a new Java class, for example,
ArchUnitTest.java. We’ll place all the tests there for the sake of simplicity.
Naming conventions tests
If you have multiple modules, you can point which package to scan using the annotation
For example, you might want to be consistent in all SpringBoot projects that the Application class name should be “MainApp”:
As you can see, the code is self-explanatory. You only have to provide the annotation ArchUnit needs to validate against, and the verification works out-of-the-box.
You can check if all Controller classes have the suffix “Controller”:
Note that the
allowEmptyShould(true) option allows tests to fail if the given project contains no controllers.
Package location tests
You might want to check if the entities reside in the “model” package:
Note that you could have the following structure:
The test will be valid because the entities reside in the “entity” which is under the “model” package.
Similarly, you can check if the configuration classes reside in the “config” package:
Note that you can easily chain multiple conditions if you need to make the rule more sophisticated.
If you want to validate all classes that extend a parent class, you can achieve it this way:
In this example, all classes that extend the
SoapRequest.class will be validated.
The following example illustrates the check for a valid annotation:
All configuration classes should have either of the desired annotations.
Software design pattern tests
Let’s say that your project should follow the Onion architecture style:
Sometimes you don’t want to execute the rules for certain classes. Typically, for JUnit tests.
This can be easily achieved by the following:
Or maybe you have a class you want to ignore because the rules don’t apply to it. Create a custom rule and import it, as shown in the above example.
Congratulations! You now know why testing the architecture is essential.
You learned how to integrate the ArchUnit testing framework into your Java projects. You also got familiar with typically used rules that you can apply in your architectural guidelines.
Check out the References section below for more rule examples.
I hope that this tutorial has been helpful. If you want to read more about software architecture best practices, you might like my other article:
Thanks for reading, and happy coding!