Software architecture tends to be esoteric and intangible. The result of this is architectural drift, with the architecture losing the qualities it was promoting as the code evolves. This talk will introduce ArchUnit, a library that allows you to test your Java architecture. You&#...
From Confoo 2021.
Software architecture tends to be esoteric and intangible. The result of this is architectural drift, with the architecture losing the qualities it was promoting as the code evolves. This talk will introduce ArchUnit, a library that allows you to test your Java architecture. You'll see how to write unit tests that protect architectural characteristics in your code while making your architecture easier to understand for everyone in your team.
Size: 3.13 MB
Language: en
Added: Feb 25, 2021
Slides: 43 pages
Slide Content
Jeremy Cook
Unit test your Java Architecture
with ArchUnit
What, why and how to unit test your architecture
Agenda
1.What is ArchUnit?
2.Why do I want to test my architecture?
3.ArchUnit overview
4.Limitations
ArchUnit Website
“ArchUnit is a free, simple and extensible library
for checking the architecture of your Java
code using any plain Java unit test framework”
Why do I want to test my
architecture?
Problems architects face
Architecture is intangible
Knowing the design is implemented
Systems tend towards entropy over time
Architectural erosion ➡ loss of architectural characteristics
Fitness functions can help
Building Evolutionary Architectures by Neal Ford, Rebecca Parsons and Patrick Kua
“An architectural fitness function provides
objective integrity of some architectural
characteristic(s)”
Architectural
Characteristics
Performance
Scalability
Durability
Accessibility
Fault tolerance
Elasticity
Stability
Evolvability
Maintainability
Comprehensibility
Testability
Verifiable with
ArchUnit
*Not an exhaustive list
Architectural
Characteristics*
ArchUnit allows fitness functions to be
created that verify and protect architectural
characteristics expressed in code
How ArchUnit helps
Architecture as code ➡ tangible architecture
Architecture violations ➡ build failures
Harder to unintentionally change design
Verifiable with
Static Analysis
Verifiable with
ArchUnit
Verifiable with
Static Analysis
Verifiable with
ArchUnit
ArchUnit overview
Anatomy of an ArchUnit test
1.Find code to verify
2.Create one or more rules
3.Check code against rules
private final JavaClasses classes = new ClassFileImporter()
.importPackages(“com.myapp.somepackage”, “com.myapp.other” );
private final JavaClasses classes = new ClassFileImporter()
.importPackages(“com.myapp.somepackage”, “com.myapp.other” );
@Test
public void checkServiceDependencies () {
}
classes().that().resideInAPackage(“..service..”)
.should().onlyHaveDependentClassesThat ()
.resideInAnyPackage("..controller..", “..service..”)
.check(classes);
Identifying code to test
Using ClassFileImporter
Import by class, classpath, JAR, location, package name, packages of class(es),
URL and path
Resolves dependencies of imported code
Filter imported code by location
private final JavaClasses classes = new ClassFileImporter()
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.withImportOption(location -> !location.contains("foo"))
.withImportOption(location -> location.matches(Pattern.compile(“.*“)))
.importClasspath();
Working with Rules
ArchUnit rules
CODE UNITS (classes, methods, fields, constructors, code units, etc)
THAT meet one or more conditions (optional)
SHOULD have one or more architectural characteristics
Customizing failure messages
ArchUnit uses method names in rules for error messages
Customizable in two ways:
•Append text with .because()
•Replace error message with.as()
@Test
public void publicStaticFieldsShouldBeFinal () {
}
fields().that().arePublic()
.and().areStatic()
.should().beFinal()
.because("mutable public state is not a good idea" )
.check(classes);
@Test
public void publicStaticFieldsShouldBeFinal () {
}
fields().that().arePublic()
.and().areStatic()
.should().beFinal()
.because("mutable public state is not a good idea" )
.check(classes);
@Test
public void publicStaticFieldsShouldBeFinal () {
}
fields().that().arePublic()
.and().areStatic()
.should().beFinal()
.as("Don't give public fields mutable state" )
.check(classes);
@Test
public void publicStaticFieldsShouldBeFinal () {
}
fields().that().arePublic()
.and().areStatic()
.should().beFinal()
.as("Don't give public fields mutable state" )
.check(classes);
Creating custom rules
CODE UNITS (classes, methods, fields, constructors, code units, etc)
THAT meet one or more conditions
SHOULD have one or more architectural characteristics
Creating custom rules
CODE UNITS (classes, methods, fields, constructors, code units, etc)
DESCRIBED PREDICATES {THAT meet one or more conditions}
SHOULD have one or more architectural characteristics
Creating custom rules
CODE UNITS (classes, methods, fields, constructors, code units, etc)
DESCRIBED PREDICATES {THAT meet one or more conditions}
ARCH CONDITIONS {SHOULD have one or more architectural characteristics}
Creating custom rules
Create DescribedPredicates and ArchConditions in two ways:
1.Compose using built in library functions
2.Extend to create custom classes
Testing architectural layers
Can be done manually
Three specialized rule types for checking layers:
•Check lower packages do not depend on upper packages
•Define layers and check dependencies between them
•Testing onion architectures
Adding ArchUnit to existing codebases
How can you add architecture tests to existing code that has violations?
1.Ignoring violations based on patterns
2.Freezing architecture rules
var rule = fields().that().arePublic()
.and().areStatic()
.should().beFinal();
FreezingArchRule.freeze(rule)
.check(classes);
Other features
•Check code against PlantUML diagrams
•Options to manage dependencies outside of diagram
•Identify and test slices of an application:
•Check for cycles
•Check slices do not depend on each other
Limitations
Cannot test all architectural
characteristics
Does not ensure maintainability
on its own
Can only check (some) JVM
languages
Importing large amounts of code
More information
ArchUnit website: https://www.archunit.org
Sample project: https://github.com/TNG/ArchUnit-Examples
Questions?
Thank you
Feel free to reach out to me
•Twitter @JCook21
•[email protected]