Comment on page
Getting Started
The following example provides the minimum setup for writing a Konsist test.
Add
mavenCentral
repository:repositories {
mavenCentral()
}
To use Konsist, include the Konsist dependency from Maven Central:
Gradle (Kotlin)
Gradle (Groovy)
Maven
More
Add the following dependency to the
module\build.gradle.kts
file:dependencies {
testImplementation("com.lemonappdev:konsist:0.13.0")
}
Add the following dependency to the
module\build.gradle
file:dependencies {
testImplementation "com.lemonappdev:konsist:0.13.0"
}
Add the following dependency to the
module\pom.xml
file:<dependency>
<groupId>com.lemonappdev</groupId>
<artifactId>konsist</artifactId>
<version>0.13.0</version>
<scope>test</scope>
</dependency>
Dependency can be added to other build systems as well. Check the snippets section in the Sonatype repository.
To achieve better test separation Konsist can be configured inside a
konsistTest
source set or a dedicated module. See Isolate Konsist Tests.At a high-level Konsist check is a Unit test following multiple implicit steps.
3 steps are required for a declaration check and 4 steps are required for an architecture check:
The declaration represents Kotlin declaration eg. Kotlin class is represented by
KoClassDeclaration
allowing to access class name (koClassDeclaration.name
), methods (koClassDeclaration.functions()
), etc. See Declaration.The first step is to get a list of Kotlin files to be verified. This step is common for declaration checks and architecture checks.
The
Konsist
object is an entry point to the Konsist framework. The scopeFromProject
method obtains the instance of the scope containing all Kotlin project files present in the project:Konsist.scopeFromProject() // Define the scope containing all Kotlin files present in the project
The following sections will present how to use a scope by writing declaration checks and architecture checks.
Let's write a simple test to verify that classes (class declarations) annotated with the
RestController
annotation resides in controller
package.To write this declaration check query all classes present in the scope:
Konsist.scopeFromProject()
.classes() // Get scope classes
Perform additional filtering to get classes annotated with
RestController
annotation:Konsist.scopeFromProject()
.classes()
.withAllAnnotationsOf(RestController::class) // Filter classes annotated with 'RestController'
Assert is the final step to perform declaration verification - use
assert
combined with koClass.resideInPackage
method to make sure that all classes (filtered in the previous step) reside in controller
package:Konsist.scopeFromProject()
.classes()
.withAllAnnotationsOf(RestController::class)
.assertTrue { it.resideInPackage("..controller") } // Define the assertion
The double dot syntax (
..)
means zero or more packages - controller package preceded by any number of packages (seePackage Wildcard syntax).The above code describes declaration consistency logic. To guard this logic (and ideally, check it with every Pull Request) it will be executed in the form of a test. Konsist code can be wrapped in the test using popular testing frameworks:
JUnit
Kotest
class ControllerClassKonsistTest {
@Test
fun `classes annotated with 'RestController' annotation reside in 'controller' package`() {
Konsist.scopeFromProject() // 1. Create a scope representing the whole project (all Kotlin files in project)
.classes() // 2. Get scope classes
.withAllAnnotationsOf(RestController::class) // 2. Filter classes annotated with 'RestController'
.assertTrue { it.resideInPackage("..controller..") } // 3. Define the assertion
}
}
The JUnit testing framework project dependency should be added to the project. See starter projects to get a complete sample project.
class ControllerClassKonsistTest : FreeSpec({
"classes annotated with 'RestController' annotation reside in 'controller' package" {
Konsist.scopeFromProject() // 1. Create a scope representing the whole project (all Kotlin files in project)
.classes() // 2. Get scope classes
.withAllAnnotationsOf(RestController::class) // 2. Filter classes annotated with 'RestController'
.assertTrue (
testName = this.testCase.name.testName
) {
it.resideInPackage("..controller..")
} // 3. Define the assertion
}
})
For Kotest to function correctly the Kotest test name has to be explicitly passed. See theKotest Support page.
The Kotest testing framework project dependency should be added to the project. See starter projects to get a complete sample project.
The above snippets present a complete example of a test verifying that all classes annotated with
RestController
annotation reside in the controller
package. Since scope is created from all project files this test will verify existing and new classes.Notice that test class has a
KonsistTest
suffix. This is the recommended approach to name Konsist tests.The above test will execute multiple assertions per test (all controllers will be verified in a single test). If you prefer better isolation each assertion can be executed as a separate test. See theDynamic Konsist Tests page.
Let's write a simple test to verify that application architecture rules are preserved. In this scenario, the application follows a simple 3-layer architecture, where
Presentation
layer depends on Business
layer and Business
layer depends on Data
layer. The Data
layer has no layer dependencies:Use
assertArchiteture
method combined with architecture definition to make sure that all classes meet architectural criteria:Konsist
.scopeFromProject()
.assertArchitecture { // Assert architecture
}
Create layers instances to represent project layers. Each
Layer
instance accepts the name
(used for presenting architecture violation errors) and package
used to define layers.Konsist
.scopeFromProject()
.assertArchitecture {
// Define layers
private val presentation = Layer("Presentation", "com.myapp.presentation..")
private val business = Layer("Business", "com.myapp.business..")
private val data = Layer("Data", "com.myapp.data..")
}
The presence of two dots at the end signifies that the layer is encompassed by the
com.myapp.business
package along with its sub-packages.The final step is to define the relations between each layer:
Konsist
.scopeFromProject()
.assertArchitecture {
private val presentation = Layer("Presentation", "com.myapp.presentation..")
private val business = Layer("Business", "com.myapp.business..")
private val data = Layer("Data", "com.myapp.data..")
// Define architecture assertions
presentation.dependsOn(business)
business.dependsOn(data)
data.dependsOnNothing()
}
The above code describes architecture consistency logic. Same as with the declaration check this logic should be executed as a unit test using you preferred testing framework:
JUnit
Kotest
class ArchitectureKonsistTest {
@Test
fun `architecture layers have dependencies correct`() {
Konsist
.scopeFromProject() // Define the scope containing all Kotlin files present i
.assertArchitecture { // Assert architecture
// Define layers
private val presentation = Layer("Presentation", "com.myapp.presentation..")
private val business = Layer("Business", "com.myapp.business..")
private val data = Layer("Data", "com.myapp.data..")
// Define architecture assertions
presentation.dependsOn(business)
business.dependsOn(data)
data.dependsOnNothing()
}
}
}
The JUnit testing framework project dependency should be added to the project. See starter projects to get a complete sample project.
class ArchitectureKonsistTest {
class UseCaseTest : FreeSpec({
"architecture layers have dependencies correct" {
Konsist
.scopeFromProject() // Define the scope containing all Kotlin files present i
.assertArchitecture() { // Assert architecture
// Define layers
val presentation = Layer("Presentation", "com.myapp.presentation..")
val business = Layer("Business", "com.myapp.business..")
val data = Layer("Data", "com.myapp.data..")
// Define architecture assertions
presentation.dependsOn(business)
business.dependsOn(data)
data.dependsOnNothing()
}
}
})
}
For Kotest to function correctly the Kotest test name has to be explicitly passed. See theKotest Support page.
The Kotest testing framework project dependency should be added to the project. See starter projects to get a complete sample project.
For more Konsist architectural checks see Protect Kotlin Project Architecture Using Konsist article.
This is the basic way of using Konsist. Take a look at this guide describing how to debug Konsist tests Debug Konsist Test to get a better understanding of how Konsist works.
Please review the Konsist documentation (this website) to read about more advanced topics and various use cases.
Last modified 27d ago