Home » Java » Core Java » Validating code and architecture constraints with ArchUnit

About Michael Scharhag

Michael Scharhag
Michael Scharhag is a Java Developer, Blogger and technology enthusiast. Particularly interested in Java related technologies including Java EE, Spring, Groovy and Grails.

Validating code and architecture constraints with ArchUnit

Introduction

ArchUnit is a library for checking Java code against a set of self defined code and architecture constraints. These constraints can be defined in a fluent Java API within unit tests. ArchUnit can be used to validate dependencies between classes or layers, to check for cyclic dependencies and much more. In this post we will create some example rules to see how we can benefit from ArchUnit.

Required dependency

To use ArchUnit we need to add the following dependency to our project:

1
2
3
4
5
6
<dependency>
    <groupId>com.tngtech.archunit</groupId>
    <artifactId>archunit-junit5</artifactId>
    <version>0.13.0</version>
    <scope>test</scope>
</dependency>

If you are still using JUnit 4 you should use the archunit-junit4 artifact instead.

Creating the first ArchUnit rule

Now we can start creating our first ArchUnit rule. For this we create a new class in our test folder:

01
02
03
04
05
06
07
08
09
10
@RunWith(ArchUnitRunner.class//only for JUnit 4, not needed with JUnit 5
@AnalyzeClasses(packages = "com.mscharhag.archunit")
public class ArchUnitTest {
 
    // verify that classes whose name name ends with "Service" should be located in a "service" package
    @ArchTest
    private final ArchRule services_are_located_in_service_package = classes()
            .that().haveSimpleNameEndingWith("Service")
            .should().resideInAPackage("..service");
}

With @AnalyzeClasses we tell ArchUnit which Java packages should be analyzed. If you are using JUnit 4 you also need to add the ArchUnit JUnit runner.

Inside the class we create a field and annotate it with @ArchTest. This is our first test.

We can define the constraint we want to validate by using ArchUnits fluent Java API. In this example we want to validate that all classes whose name ends with Service (e.g. UserService) are located in a package named service (e.g. foo.bar.service).

Most ArchUnit rules start with a selector that indicates what type of code units should be validated (classes, methods, fields, etc.). Here, we use the static method classes() to select classes. We restrict the selection to a subset of classes using the that() method (here we only select classes whose name ends with Service). With the should() method we define the constraint that should be matched against the selected classes (here: the classes should reside in a service package).

When running this test class all tests annotated with @ArchTest will be executed. The test will fail, if ArchUnits detects service classes outside a service package.

More examples

Let’s look at some more examples.

We can use ArchUnit to make sure that all Logger fields are private, static and final:

1
2
3
4
5
6
7
// verify that logger fields are private, static and final
@ArchTest
private final ArchRule loggers_should_be_private_static_final = fields()
        .that().haveRawType(Logger.class)
        .should().bePrivate()
        .andShould().beStatic()
        .andShould().beFinal();

Here we select fields of type Logger and define multiple constraints in one rule.

Or we can make sure that methods in utility classes have to be static:

1
2
3
4
5
// methods in classes whose name ends with "Util" should be static
@ArchTest
static final ArchRule utility_methods_should_be_static = methods()
        .that().areDeclaredInClassesThat().haveSimpleNameEndingWith("Util")
        .should().beStatic();

To enforce that packages named impl contain no interfaces we can use the following rule:

1
2
3
4
5
// verify that interfaces are not located in implementation packages
@ArchTest
static final ArchRule interfaces_should_not_be_placed_in_impl_packages = noClasses()
        .that().resideInAPackage("..impl..")
        .should().beInterfaces();

Note that we use noClasses() instead of classes() to negate the should constraint.

(Personally I think this rule would be much easier to read if we could define the rule as interfaces().should().notResideInAPackage(“..impl..”). Unfortunately ArchUnit provides no interfaces() method)

Or maybe we are using the Java Persistence API and want to make sure that EntityManager is only used in repository classes:

1
2
3
4
@ArchTest
static final ArchRule only_repositories_should_use_entityManager = noClasses()
        .that().resideOutsideOfPackage("..repository")
        .should().dependOnClassesThat().areAssignableTo(EntityManager.class);

Layered architecture example

ArchUnit also comes with some utilities to validate specific architecture styles.

For example can we use layeredArchitecture() to validate access rules for layers in a layered architecture:

1
2
3
4
5
6
7
8
@ArchTest
static final ArchRule layer_dependencies_are_respected = layeredArchitecture()
        .layer("Controllers").definedBy("com.mscharhag.archunit.layers.controller..")
        .layer("Services").definedBy("com.mscharhag.archunit.layers.service..")
        .layer("Repositories").definedBy("com.mscharhag.archunit.layers.repository..")
        .whereLayer("Controllers").mayNotBeAccessedByAnyLayer()
        .whereLayer("Services").mayOnlyBeAccessedByLayers("Controllers")
        .whereLayer("Repositories").mayOnlyBeAccessedByLayers("Services");

Here we define three layers: Controllers, Services and Repositories. The repository layer may only accessed by the service layer while the service layer may only be accessed by controllers.

Shortcuts for common rules

To avoid that we have to define all rules our self, ArchUnit comes with a set of common rules defined as static constants. If these rules fit our needs, we can simply assign them to @ArchTest fields in our test.

For example we can use the predefined NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS rule if we make sure no exceptions of type Exception and RuntimeException are thrown:

1
2
@ArchTest
private final ArchRule no_generic_exceptions = NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS;

Summary

ArchUnit is a powerful tool to validate a code base against a set of self defined rules. Some of the examples we have seen are also reported by common static code analysis tools like FindBugs or SonarQube. However, these tools are typically harder to extend with your own project specific rules and this is where ArchUnit comes in.

As always you can find the Sources from the examples on GitHub. If you are interested in ArchUnit you should also check the comprehensive user guide.

Published on Java Code Geeks with permission by Michael Scharhag, partner at our JCG program. See the original article here: Validating code and architecture constraints with ArchUnit

Opinions expressed by Java Code Geeks contributors are their own.

(0 rating, 0 votes)
You need to be a registered member to rate this.
4 Comments Views Tweet it!
Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

4
Leave a Reply

avatar
4 Comment threads
0 Thread replies
1 Followers
 
Most reacted comment
Hottest comment thread
4 Comment authors
Builders Rotoruaarchitects aucklandAndriyElena Gillbert Recent comment authors

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
newest oldest most voted
Notify of
Elena Gillbert
Guest

Hi… A common problem faced by development organizations is that code implementations can often diverge from the original design and architecture. The problem is common enough, especially on large projects, that a new tool has emerged to help test that a code implementation is consistent with the originally defined architecture. ArchUnit is a small, simple, extensible, open source Java testing library for verifying predefined application architecture characteristics and architectural constraints. An ArchUnit test is written and runs as a unit test that gives developers and application architects fast feedback on their work. It guarantees that a software build will break… Read more »

Andriy
Guest

Whether any advantages ArchUnit over static code analysis tools like CheckStyle or PMD? Anyway, thank you for the article!

architects auckland
Guest

An amazing article. It’s nice to read a quality blog post. “Java Code Geeks”. I think you made some good points in this post.

Builders Rotorua
Guest

Hey there, first of all, thank you so much for this post and honestly, I was searching for the same information from the last few days. “Molding with mud Eugene Pandala’s tryst with sustainable architecture”. Keep posting and keep sharing.