All pages
Powered by GitBook
1 of 4

Loading...

Loading...

Loading...

Loading...

Getting Started

The following example provides the minimum setup for defining and running a single Konsist test.

Check the starter projects containing Konsist tests or review the Konsist API reference.

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

Create First Konsist Test - Declaration Check

Konsist Declaration Checks provide a powerful mechanism for validating the structural elements of the Kotlin codebase. These checks allow developers to enforce structural rules and coding conventions by verifying classes, interfaces, functions, properties, and other code declarations. Here few things that can be verified with Konsist:

  • All Use cases should reside in usecase specific package

  • Repository classes must implement Repository interface

  • All repository classes should have name ending with Repository

  • data classes should have only val properties

  • Test classes should have test subject named sut

  • ...

See section for more examples.

Write First Declaration Check

Let's write a simple test to verify that all classes (all class declarations) residing in resides in controller package are annotated with the RestController annotation .

Overview

On a high level writing Konsist declaration check requires 4 steps:

Let's take a closer look at each of these steps.

1. Create The Scope

The first step is to get a list of Kotlin files to be verified.

The Konsist object is an entry point to the Konsist library.

The scopeFromX methods obtains the instance of the scope containing Kotlin project files. To get all Kotlin project files present in the project use the scopeFromProject method:

To define more granular scopes such as scope from production code or scope from single module see the page.

2. Retrieve Declarations

Each file in the scope contains set of declarations like classes, properties functions etc. (see ). To write this declaration check for all classes present in the scope query classes using classes method :

3. Filter Declarations

In this project controllers are defined as classes annotated with RestController annotation. Use withAllAnnotationsOf method to filter classes with with RestController annotation:

To perform more granular querying and filtering see the page.

4. Define Assertion

To performa assertion use the assertTrue method:

To verify that classes are located in the controller package, use the resideInPackage method inside assertTrue block:

This verification applies to the entire collection of previously filtered classes, rather than examining just one class in isolation.

To learn more about assertions see page.

The double dot syntax (..) means zero or more packages - controller package preceded by any number of packages (see syntax).

Wrap Konsist Code In Test

The declaration validation logic should be protected through automated testing. By wrapping Konsist checks within standard testing frameworks such as or , you can verify these rules with each :

The testing framework project dependency should be added to the project. See to get a complete sample project.

For Kotest to function correctly the Kotest test name has to be explicitly passed. See the page.

Note that test class has a KonsistTest suffix. This is the recommended approach to name classes containing Konsist tests.

Summary

This section described the basic way of writing Konsist declaration test. To get a better understanding of how Konsist API works see and sections.

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 the page.

The Kotest testing framework project dependency should be added to the project. See starter projects to get a complete sample project.

Snippets
Create The Scope
Declaration
Declaration Filtering
Declaration Assertion
Package Wildcard
JUnit
KoTest
Pull Request
JUnit
starter projects
Kotest Support
https://github.com/LemonAppDev/konsist-documentation/blob/main/getting-started/getting-started/broken-reference/README.md
Debug Konsist Test
Dynamic Konsist Tests

Add Konsist Dependency

Add Maven Central Repository

Add mavenCentral repository:

Add Konsist Dependency

Konsist
 // Define the scope containing all Kotlin files present in the project
Konsist.scopeFromProject() //Returns KoScope
Konsist.scopeFromProject()
    // Get scope classes
    .classes() 
Konsist.scopeFromProject()
    .classes()
    // Filter classes annotated with 'RestController'
    .withAllAnnotationsOf(RestController::class) 
Konsist.scopeFromProject()
    .classes()
    .withAllAnnotationsOf(RestController::class)
    .assertTrue { 
        // Define the assertion
    } 
Konsist.scopeFromProject()
    .classes()
    .withAllAnnotationsOf(RestController::class)
    .assertTrue { 
       // Check if classes are located in the controller package
        it.resideInPackage("..controller") 
    } 
class ControllerClassKonsistTest {
    @Test
    fun `classes annotated with 'RestController' annotation reside in 'controller' package`() {
      // 1. Create a scope representing the whole project (all Kotlin files in project)
            Konsist.scopeFromProject()
            // 2. Retrieve class declarations
            .classes()
            // 3. Filter classes annotated with 'RestController'
            .withAllAnnotationsOf(RestController::class)
            // 4. Define the assertion
            .assertTrue { it.resideInPackage("..controller..") }
    }
}
class ControllerClassKonsistTest : FreeSpec({
    "classes annotated with 'RestController' annotation reside in 'controller' package" {
         Konsist
            // 1. Create a scope representing the whole project (all Kotlin files in project)
            .scopeFromProject()
            // 2. Retrieve class declarations
            .classes() // 2. Get scope classes
            // 3. Filter classes annotated with 'RestController'
            .withAllAnnotationsOf(RestController::class)
            // 4. Define the assertion
            .assertTrue (testName = this.testCase.name.testName) { 
                it.resideInPackage("..controller..") 
            }
    }
})
To use Konsist, include the Konsist dependency from Maven Central:

Add the following dependency to the module\build.gradle.kts file:

dependencies {
    testImplementation("com.lemonappdev:konsist:0.17.3")
}

Add the following dependency to the module\build.gradle file:

dependencies {
    testImplementation "com.lemonappdev:konsist:0.17.3"
}

Add the following dependency to the module\pom.xml file:

<dependency>
    <groupId>com.lemonappdev</groupId>
    <artifactId>konsist</artifactId>
    <version>0.17.3</version>
    <scope>test</scope>
</dependency>

See Compatibilityto learn how Konsist integrates with Kotlin ecosystem.

To achieve better test separation Konsist can be configured inside a customkonsistTest source set or a dedicated konsistTest module. See Isolate Konsist Tests for guidelines on how to store Konsist test in project codebase and how to run them using cmd.

repositories {
    mavenCentral()
}

Create Secound Konsist Test - Architectural Check

Konsist's Architectural Checks serve as a robust tool for maintaining layer isolation, enabling development teams to enforce strict boundaries between different architectural layers. Here few things that can be verified with Konsist:

  • domain layer is independant

  • data layer depends on domain layer

  • ...

See section for more examples.

Write First Architectural Check

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 and Data layers depend on Domain layer and Domain layer is independant (from these layers):

Overview

On a high level writing Konsist architectural check requires 3 steps:

Let's take a closer look at each of these steps.

1. Define Layers

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.

The double dot syntax (..) means zero or more packages - layer is represented by the package and all of it's sub packages (see syntax).

2. Create The Scope

The Konsist object is an entry point to the Konsist library.

The scopeFromX methods obtains the instance of the scope containing Kotlin project files. To get all Kotlin project files present in the project use the scopeFromProject method:

To define more granular scopes such as scope from production code or scope from single module see the page.

3. Assert Architecture

To performa assertion use the assertArchiteture method:

Utilize dependsX methods to validate that your project's layers adhere to the defined architectural dependencies:

Wrap Konsist Code In Test

The declaration validation logic should be protected through automated testing. By wrapping Konsist checks within standard testing frameworks such as or , you can verify these rules with each :

The testing framework project dependency should be added to the project. See to get a complete sample project.

For Kotest to function correctly the Kotest test name has to be explicitly passed. See the page.

Note that test class has a KonsistTest suffix. This is the recommended approach to name classes containing Konsist tests.

Summary

This section described the basic way of writing Konsist architectural test. To get a better understanding of how Konsist API works see .

The Kotest testing framework project dependency should be added to the project. See starter projects to get a complete sample project.

Architecture Snippets
Package Wildcard
Create The Scope
JUnit
KoTest
Pull Request
JUnit
starter projects
Kotest Support
Debug Konsist Test
// Define layers
private val presentationLayer = Layer("Presentation", "com.myapp.presentation..")
private val domainLayer = Layer("Domain", "com.myapp.domain..")
private val dataLayer = Layer("Data", "com.myapp.data..")
Konsist
// Define layers
private val presentationLayer = Layer("Presentation", "com.myapp.presentation..")
private val domainLayer = Layer("Domain", "com.myapp.domain..")
private val dataLayer = Layer("Data", "com.myapp.data..")
 
// Define the scope containing all Kotlin files present in the project
Konsist.scopeFromProject() //Returns KoScope
// Define layers
private val presentationLayer = Layer("Presentation", "com.myapp.presentation..")
private val domainLayer = Layer("Domain", "com.myapp.domain..")
private val dataLayer = Layer("Data", "com.myapp.data..")

Konsist
    .scopeFromProject()
     // Assert architecture
    .assertArchitecture {
        // Define architectural rules
    }
Konsist
    .scopeFromProject()
    .assertArchitecture {
        private val presentationLayer = Layer("Presentation", "com.myapp.presentation..")
        private val domainLayer = Layer("Domain", "com.myapp.business..")
        private val dataLayer = Layer("Data", "com.myapp.data..")

        // Define layer dependnecies
        presentationLayer.dependsOn(domainLayer)
        dataLayer.dependsOn(domainLayer)
        domainLayer.dependsOnNothing()
    }
class ArchitectureKonsistTest {
    @Test
    fun `architecture layers have dependencies correct`() {
        Konsist
            .scopeFromProject()
            .assertArchitecture {
                private val presentationLayer = Layer("Presentation", "com.myapp.presentation..")
                private val domainLayer = Layer("Domain", "com.myapp.business..")
                private val dataLayer = Layer("Data", "com.myapp.data..")
        
                // Define layer dependnecies
                presentationLayer.dependsOn(domainLayer)
                dataLayer.dependsOn(domainLayer)
                domainLayer.dependsOnNothing()
            }
    }
}
class ArchitectureKonsistTest {
    class UseCaseTest : FreeSpec({
        "architecture layers have dependencies correct" {
            Konsist
                .scopeFromProject()
                .assertArchitecture {
                    private val presentationLayer = Layer("Presentation", "com.myapp.presentation..")
                    private val domainLayer = Layer("Domain", "com.myapp.business..")
                    private val dataLayer = Layer("Data", "com.myapp.data..")
            
                    // Define layer dependnecies
                    presentationLayer.dependsOn(domainLayer)
                    dataLayer.dependsOn(domainLayer)
                    domainLayer.dependsOnNothing()
                }
        }
    })
}