Architecture assertions are used to perform architecture verification. It is the final step of Konsist verification preceded by scope creation (Create The Scope):
Assert Architecture
As an example, this simple 2-layer architecture will be used:
The assertArchitecture block defines architecture layer rules and verifies that the layer requirements are met.
Create Layer class instance to represent project layers. Each Layer instance accepts the name (used for presenting architecture violation errors) and package used to define architectural layer:
By default dependsOn method works like does not perform strict layer validation (strict = false). However this behaviour is controlled b ystrict parameter:
strict = false (default) - may depend on layer
strict = true - have to depend on layer
e.g.
// Optional dependency - Feature layer may depend on Domain layerfeatureLayer.dependsOn(domainLayer) // strict = false by default// Required dependency - Feature layer must depend on Domain layerfeatureLayer.dependsOn(domainLayer, strict =true)
Excluding Files
Architecture verification can be performed on KoScope (as seen above) and a list containing KoFiles. For example, you can remove a few files from the scope before performing an architectural check:
This approach provides more flexibility when working with complex projects, however, The desired approach is to create a dedicated scope. See Create The Scope.
Include Layer Without Defining Dependency
The include method allows to include layer in architecture verification, without defining a dependency for this layer:
privateval domain =Layer("Domain", "com.domain..")privateval presentation =Layer("Presentation", "com..presentation..")Konsist .scopeFromProject() scope.assertArchitecture {// Include presentation for architectural check without defining a dependency presentation.include()// Include domain layer or architectural check and define no dependency (independent) domain.doesOnNothing() }}
Architecture As A Variable
Architecture configuration can be defined beforehand and stored in a variable to facilitate checks for multiple scopes:
// Define architectureval architecture =architecture {val presentation =Layer("Presentation", "com.myapp.presentation..")valdata=Layer("Data", "com.myapp.data..") presentation.dependsOn(data)data.dependsOnNothing()}// Assert Architecture of two modules using common architecture rulesmoduleFeature1Scope.assertArchitecture(architecture)moduleFeature2Scope.assertArchitecture(architecture)
This approach may be helpful when refactoring existing applications. To facilitate readability the above checks should be expressed as two unit tests:
classArchitectureTest {privateval architecture =architecture {val presentation =Layer("Presentation", "com.myapp.presentation..")valdata=Layer("Data", "com.myapp.data..") presentation.dependsOn(data)data.dependsOnNothing() }@Testfun`architecture layers of feature1 module have dependencies correct`() { moduleFeature1Scope.assertArchitecture(architecture) }@Testfun`architecture layers of feature2 module have dependencies correct`() { moduleFeature2Scope.assertArchitecture(architecture) }}