add arch test for layer structure

This commit is contained in:
Savosin Denis
2025-06-03 17:40:32 +07:00
parent d4e36e7354
commit 6b03b7a01a
3 changed files with 64 additions and 0 deletions

View File

@@ -89,6 +89,8 @@ dependencies {
implementation(libs.springBoot.starter.mustache) implementation(libs.springBoot.starter.mustache)
implementation(libs.springBoot.starter.web) implementation(libs.springBoot.starter.web)
testImplementation(libs.archUnit.junit)
developmentOnly(libs.springBoot.devtools) developmentOnly(libs.springBoot.devtools)
kover(project(":edge-contracts")) kover(project(":edge-contracts"))

View File

@@ -7,6 +7,7 @@ spring-cloud = "4.1.5"
testcontainers = "1.19.7" testcontainers = "1.19.7"
[libraries] [libraries]
archUnit-junit = { module = "com.tngtech.archunit:archunit-junit5", version = "1.4.1" }
flyway-core = { module = "org.flywaydb:flyway-core", version = "9.22.3" } flyway-core = { module = "org.flywaydb:flyway-core", version = "9.22.3" }
jackson-datatype-jsr = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310", version.ref = "jackson" } jackson-datatype-jsr = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310", version.ref = "jackson" }
jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" } jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" }

View File

@@ -0,0 +1,61 @@
package com.github.dannecron.demo
import com.tngtech.archunit.core.importer.ClassFileImporter
import com.tngtech.archunit.core.importer.ImportOption
import com.tngtech.archunit.library.Architectures
import org.junit.jupiter.api.Test
class ArchTest {
companion object {
// high-level layers
private const val LAYER_EDGE_CONSUMING = "edge-consuming"
private const val LAYER_EDGE_REST = "edge-rest"
// core
private const val LAYER_CORE = "core"
// low-level layers
private const val LAYER_DB = "db"
private const val LAYER_EDGE_INTEGRATIONS = "edge-integrations"
private const val LAYER_EDGE_PRODUCING = "edge-producing"
// edge-contracts
private const val LAYER_EDGE_CONTRACTS = "edge-contracts"
}
private val config: List<Triple<String, String, List<String>>> = listOf(
Triple(LAYER_EDGE_CONSUMING, "edgeconsuming", emptyList()),
Triple(LAYER_EDGE_REST, "edgerest", emptyList()),
Triple(LAYER_CORE, "core", listOf(LAYER_EDGE_CONSUMING, LAYER_EDGE_REST)),
Triple(LAYER_DB, "db", listOf(LAYER_CORE)),
Triple(LAYER_EDGE_INTEGRATIONS, "edgeintegration", listOf(LAYER_CORE)),
Triple(LAYER_EDGE_PRODUCING, "edgeproducing", listOf(LAYER_CORE)),
Triple(
LAYER_EDGE_CONTRACTS,
"edgecontracts",
listOf(LAYER_EDGE_INTEGRATIONS, LAYER_EDGE_PRODUCING, LAYER_EDGE_CONSUMING, LAYER_EDGE_REST),
),
)
@Test
fun `check layers`() {
val mainSrcPackage = this::class.java.packageName
val allProjectClasses = ClassFileImporter()
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.importPackages(mainSrcPackage)
Architectures.layeredArchitecture()
.consideringAllDependencies().let { arch ->
config.fold(arch) { archLocal, conf ->
val (layerName, layerNamespace, acceptedByLayers) = conf
archLocal.layer(layerName).definedBy("$mainSrcPackage.$layerNamespace..").let {
if (acceptedByLayers.isNotEmpty())
it.whereLayer(layerName).mayOnlyBeAccessedByLayers(*acceptedByLayers.toTypedArray())
else
it
}
}
}.also {
it.check(allProjectClasses)
}
}
}