What does ApplicationModules.verify() do in Spring Modulith, and how do you wire it into a test?
answer
- ApplicationModules.of(App.class).verify()
- direct sub-package = one module
- ArchUnit-backed, no Spring context
- fails on cycles + internals + disallowed deps
- one JUnit test, runs in CI
basics
~20 sIt scans your application's packages, discovers each top-level package as a module, and checks that modules only depend on ones they are allowed to. You run it from a JUnit test; if a rule is broken the test fails.
solid answer
~40 sSpring Modulith treats each direct sub-package of your main application package as an 'application module'. ApplicationModules.of(MyApplication.class) builds a model of those modules from the classpath. Calling .verify() on that model asserts the structural rules: modules only reach into other modules through allowed paths, no cyclic dependencies exist, and code doesn't reach into another module's internals (non-API packages). It is backed by ArchUnit, so violations are reported as readable failures. You invoke it from a plain JUnit test — typically one small test class — so the check runs on every build and fails fast in CI. It needs no Spring context; it's pure static analysis of compiled classes, making it fast and deterministic.
code
java · 13 linesimport org.springframework.modulith.core.ApplicationModules;
import org.junit.jupiter.api.Test;
class ModularityTests {
static final ApplicationModules modules =
ApplicationModules.of(ShopApplication.class);
@Test
void verifiesModuleBoundaries() {
modules.verify(); // throws Violations if any boundary rule is broken
}
}go deeper
Know the one-liner: ApplicationModules.of(App.class).verify() in a JUnit test enforces module boundaries.
Explain what it checks (cycles, internals, allowed deps) and that it's ArchUnit-backed static analysis.
Discuss module detection rules, exposed-vs-internal packages, and why running it in CI matters.
Position it as the enforcement leg of a modular-monolith strategy and its limits (compile-time only, no reflective refs).
## Background **Spring Modulith** is a Spring project for building *modular monoliths*: one deployable app split into logical **application modules** whose boundaries are enforced at build time. A module is, by convention, a **direct sub-package** of your main application package (the one holding the `@SpringBootApplication` class). Example: if your app root is `com.example.shop`, then `com.example.shop.order` and `com.example.shop.inventory` are two modules. Within a module Modulith distinguishes: - The **API / base package** (the module's root package) — types here are *public* to other modules. - **Internal sub-packages** — anything nested deeper (e.g. `order.internal`) is considered module-private; other modules must not reference those types. ## What `verify()` actually does 1. `ApplicationModules.of(ShopApplication.class)` scans the classpath starting at the app's base package and builds an in-memory model of every module, its exposed types, and the dependencies between them. 2. `.verify()` runs a set of **structural assertions** over that model: - **No cyclic dependencies** between modules (A→B→A fails). - **Allowed-dependencies respected**: if a module declares an allow-list, it may only depend on those modules. - **No access to another module's internals**: referencing a type in another module's non-exposed (internal) package fails. - **Efferent/afferent access only through valid entry points** (respecting named interfaces, see follow-ups). If any rule is broken, `verify()` throws a `Violations` exception whose message lists each offending class/dependency, so it reads like a normal test failure. ## How it's backed Under the hood the checks are implemented with **ArchUnit** (a Java architecture-testing library). You don't write ArchUnit rules yourself — Modulith derives them from the module model. That's why it's static (no running Spring context) and fast. ## Wiring it into a test A single JUnit 5 test is the idiomatic setup: ```java class ModularityTests { ApplicationModules modules = ApplicationModules.of(ShopApplication.class); @Test void verifiesModularStructure() { modules.verify(); } } ``` Because it's a normal unit test, it runs in `./gradlew test` / `mvn test` and in CI, blocking merges that break boundaries. ## When to use it Always, once you adopt Modulith — it's the enforcement mechanism that makes module boundaries real rather than aspirational. Keep exactly one such test near the application class. ## Gotchas - It only sees **compiled classes on the classpath**; reflection-only or string-based references are invisible. - Splitting a module into deeper packages doesn't create new modules — only *direct* sub-packages of the base package are modules (unless you customize detection). - It verifies structure, **not** runtime behavior; a passing verify() says nothing about whether your events actually fire.
- Does verify() need a running Spring application context?No. It's pure static analysis over compiled classes via ArchUnit, so it runs like a fast unit test with no context bootstrap.
- What counts as an application module by default?Each direct sub-package of the main application (base) package. Deeper nested packages are treated as that module's internals, not separate modules.
saying these in an interview costs you the question
- Thinking verify() spins up the Spring context or checks runtime behavior
- Believing every nested package becomes its own module
- Claiming you must hand-write ArchUnit rules yourself