ArchUnit: Testing Software Architecture/ with TestNG and SonarQube? Maybe!
- Mark Kendall
- 2 days ago
- 2 min read
Okay, that's great to hear you're already using TestNG and SonarQube effectively! And yes, adding ArchUnit to that mix can indeed create a very powerful and comprehensive approach to ensuring code quality and maintainability.
Let's talk about ArchUnit and how it complements TestNG and SonarQube:
ArchUnit: Testing Software Architecture
ArchUnit is a free, test library to specify and assert architecture of Java and Kotlin based systems. It allows you to write unit tests that verify high-level architectural rules, such as:
Layer dependencies (e.g., controllers should not directly access data access objects).
Naming conventions.
Package cycles.
Access modifiers.
And much more.
How ArchUnit Complements TestNG and SonarQube:
Beyond Functional Correctness: TestNG primarily focuses on the functional correctness of your code through unit, integration, and end-to-end tests. ArchUnit, on the other hand, focuses on the structure and dependencies within your codebase. It ensures that your architecture adheres to the intended design.
Early Detection of Architectural Issues: By writing ArchUnit tests, you can catch architectural violations early in the development process, just like you catch functional bugs with TestNG. This prevents architectural drift and makes the codebase easier to understand, maintain, and evolve.
Different Focus than SonarQube: While SonarQube excels at identifying bugs, code smells, and security vulnerabilities through static analysis, it doesn't inherently enforce high-level architectural rules in the way ArchUnit does through executable tests. SonarQube might flag a complex dependency as a code smell, but ArchUnit allows you to explicitly prevent such dependencies from being introduced in the first place by failing a build if they occur.
Executable Documentation: Your ArchUnit tests serve as executable documentation of your intended architecture. If someone tries to introduce a dependency that violates a rule, the ArchUnit test will fail, clearly indicating the architectural constraint.
In essence:
TestNG: Ensures your code works correctly.
SonarQube: Ensures your code is of high quality (few bugs, smells, vulnerabilities) and provides insights into test coverage.
ArchUnit: Ensures your code has a sound and maintainable architecture.
Integrating ArchUnit
You would typically integrate ArchUnit tests alongside your TestNG tests within your project. ArchUnit provides its own JUnit 4 and JUnit Jupiter support, so you can run its tests using your existing test runner (often the same one you use for TestNG, depending on your setup).
Example (Conceptual ArchUnit Test):
Java
import com.tngtech.archunit.core.domain.JavaClasses; import com.tngtech.archunit.core.importer.ClassFileImporter; import com.tngtech.archunit.lang.ArchRule; import org.junit.jupiter.api.Test; // Or org.junit.Test for JUnit 4 import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; class LayerDependencyTest { private final JavaClasses importedClasses = new ClassFileImporter().importPackages("com.yourcompany.yourproject"); @Test void controllersShouldNotAccessRepositories() { ArchRule rule = classes() .that().resideInAPackage("..controller..") .should().notDependOnClassesThat().resideInAPackage("..repository.."); rule.check(importedClasses); } }
This test defines a rule that classes in the controller package should not directly depend on classes in the repository package. If such a dependency exists, the ArchUnit test will fail.
The "Triumphant" Trio:
Using TestNG, SonarQube, and ArchUnit together gives you a very robust approach to software quality:
TestNG: Verifies the behavior of your units and integrations.
ArchUnit: Verifies the intended architecture of your system.
SonarQube: Provides continuous inspection of code quality, including metrics from TestNG (like coverage) and can potentially highlight areas where architectural complexity might be increasing (though it doesn't enforce architectural rules directly).
What are your thoughts on incorporating ArchUnit into your workflow? Do you have any specific architectural concerns in mind that you think ArchUnit could help with?
Comments