Add archunit module: ArchUnit for Spring Boot - enforcing layered architecture as a unit test

This commit is contained in:
Claude
2026-10-03 21:21:03 +00:00
parent 3d05e483cc
commit 8be1245951
17 changed files with 459 additions and 0 deletions
@@ -0,0 +1,32 @@
Captured from a real `mvn test -Dtest=FreezingArchRuleTest` run, taken immediately after
the first run (docs/output/02-freeze-run1-baseline-captured.txt) had already frozen
LegacyOrderExporter.export() into archunit_store/. Between the two runs: a second class,
NewOrderBatchJob, was added with a method making the exact same mistake
(`run() throws Exception`), and freeze.store.default.allowStoreCreation was flipped to
false in archunit.properties -- the normal CI setting once a baseline exists, so nobody
can accidentally create a fresh, empty baseline that silently un-freezes everything.
[INFO] Running com.ankurm.tutorials.junit.archunit.FreezingArchRuleTest
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 1.156 s <<< FAILURE! -- in com.ankurm.tutorials.junit.archunit.FreezingArchRuleTest
[ERROR] FreezingArchRuleTest.noNewGenericExceptionsDeclared -- Time elapsed: 1.145 s <<< FAILURE!
java.lang.AssertionError:
Architecture Violation [Priority: MEDIUM] - Rule 'no methods should declare throwable of type java.lang.Exception, because a specific exception type documents what a caller actually has to handle; `throws Exception` documents nothing' was violated (1 times):
Method <com.ankurm.tutorials.junit.archunit.service.NewOrderBatchJob.run()> does declare throwable of type java.lang.Exception in (NewOrderBatchJob.java:15)
at com.tngtech.archunit.lang.ArchRule$Assertions.assertNoViolation(ArchRule.java:94)
at com.tngtech.archunit.lang.ArchRule$Assertions.check(ArchRule.java:86)
at com.tngtech.archunit.library.freeze.FreezingArchRule.check(FreezingArchRule.java:97)
[INFO] Results:
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
[INFO] BUILD FAILURE
This is the entire point of freeze(): the violation this test reports is ONLY
NewOrderBatchJob.run(). LegacyOrderExporter.export() still declares `throws Exception`
too -- nothing about it changed -- and it is not mentioned anywhere in this failure,
because it was already recorded as accepted in archunit_store/ before this run started.
A rule that would otherwise have to fail against every pre-existing offender at once
instead fails against exactly one thing: the offender that showed up after the team
agreed to stop adding new ones.
NewOrderBatchJob was deleted immediately after this run; it was never meant to survive
past this transcript. docs/output/00- and docs/output/02- show the suite back to green
with it removed and the frozen baseline still in place.