Konsist
GitHubSlack (kotlinlang)Twitter
  • 🚀GETTING STARTED
    • What is Konsist?
    • Getting Started
      • Add Konsist Dependency
      • Create First Konsist Test - Declaration Check
      • Create Secound Konsist Test - Architectural Check
    • Articles & Videos
  • ✅WRITING TESTS
    • Create The Scope
    • Declaration Filtering
    • Declaration Assertion
    • Architecture Assertion
    • Suppress Konsist Test
  • ✏️VERYFYING CODEBASE
    • Verify Classes
    • Verify Interfaces
    • Verify Functions
    • Verify Properties
    • Verify Generics
    • Verify Source Declarations
  • 📗FEATURES
    • Add Konsist Existing To Project (Baseline)
    • Debug Konsist Test
    • Declaration
    • Declaration Vs Property
    • Compiler Type Inference
    • Package Wildcard
    • Declaration References
    • Indirect Parents
    • Kotest Support
  • 🔍INSPIRATION
    • Starter Projects
    • Snippets
      • General Snippets
      • Android Snippets
      • Spring Snippets
      • Test Snippets
      • JUnit Snippets
      • Kotest Snippets
      • Architecture Snippets
      • Clean Architecture Snippets
      • Kotlin Serialization Snippets
      • Library Snippets
      • Generic Types Snippets
  • 🎓ADVANCED
    • Isolate Konsist Tests
    • Enable Full Command Line Logging
    • Dynamic Konsist Tests
      • Explicit Test Names
    • When Konsist API Is Not Enough
    • Additional JUnit5 Setup
    • Why There Are No Pre-defined Rules?
    • Konsist Snapshots
  • ❓HELP
    • Getting Help
    • Known Issues
      • java.lang.OutOfMemoryError: Java heap space
    • Compatibility
  • ℹ️OTHER
    • Changelog
    • Project Status
    • Contributing
    • Contributors
    • Assets And Logos
    • Open Source Licenses
    • Sponsor Konsist
Powered by GitBook
On this page
  • 1. Clean Architecture Layers Have Correct Dependencies
  • 2. Classes With UseCase Suffix Should Reside In domain And usecase Package
  • 3. Classes With UseCase Suffix Should Have Single public Operator Method Named invoke
  • 4. Classes With UseCase Suffix And Parents Should Have Single public Operator Method Named invoke
  • 5. Interfaces With Repository Annotation Should Reside In data Package
  • 6. Every UseCase Class Has Test
Edit on GitHub
Export as PDF
  1. INSPIRATION
  2. Snippets

Clean Architecture Snippets

Snippets used to guard clean architecture dependencies.

1. Clean Architecture Layers Have Correct Dependencies

@Test
fun `clean architecture layers have correct dependencies`() {
    Konsist
        .scopeFromProduction()
        .assertArchitecture {
            // Define layers
            val domain = Layer("Domain", "com.myapp.domain..")
            val presentation = Layer("Presentation", "com.myapp.presentation..")
            val data = Layer("Data", "com.myapp.data..")

            // Define architecture assertions
            domain.dependsOnNothing()
            presentation.dependsOn(domain)
            data.dependsOn(domain)
        }
}

2. Classes With UseCase Suffix Should Reside In domain And usecase Package

@Test
fun `classes with 'UseCase' suffix should reside in 'domain' and 'usecase' package`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("UseCase")
        .assertTrue { it.resideInPackage("..domain..usecase..") }
}

3. Classes With UseCase Suffix Should Have Single public Operator Method Named invoke

@Test
fun `classes with 'UseCase' suffix should have single 'public operator' method named 'invoke'`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("UseCase")
        .assertTrue {
            val hasSingleInvokeOperatorMethod = it.hasFunction { function ->
                function.name == "invoke" && function.hasPublicOrDefaultModifier && function.hasOperatorModifier
            }

            hasSingleInvokeOperatorMethod && it.countFunctions { item -> item.hasPublicOrDefaultModifier } == 1
        }
}

4. Classes With UseCase Suffix And Parents Should Have Single public Operator Method Named invoke

@Test
fun `classes with 'UseCase' suffix and parents should have single 'public operator' method named 'invoke'`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("UseCase")
        .assertTrue {
            // Class and it's parent
            val declarations = listOf(it) + it.parents(true)

            // Functions from all parents without overrides
            val uniqueFunctions = declarations
                .mapNotNull { koParentDeclaration -> koParentDeclaration as? KoFunctionProvider }
                .flatMap { koFunctionProvider ->
                    koFunctionProvider.functions(
                        includeNested = false,
                        includeLocal = false
                    )
                }
                .filterNot { koFunctionDeclaration -> koFunctionDeclaration.hasOverrideModifier }

            val hasInvokeOperatorMethod = uniqueFunctions.any { functionDeclaration ->
                functionDeclaration.name == "invoke" && functionDeclaration.hasPublicOrDefaultModifier && functionDeclaration.hasOperatorModifier
            }

            val numParentPublicFunctions = uniqueFunctions.count { functionDeclaration ->
                functionDeclaration.hasPublicOrDefaultModifier
            }

            hasInvokeOperatorMethod && numParentPublicFunctions == 1
        }
}

5. Interfaces With Repository Annotation Should Reside In data Package

@Test
fun `interfaces with 'Repository' annotation should reside in 'data' package`() {
    Konsist
        .scopeFromProject()
        .interfaces()
        .withAnnotationOf(Repository::class)
        .assertTrue { it.resideInPackage("..data..") }
}

6. Every UseCase Class Has Test

@Test
fun `every UseCase class has test`() {
    Konsist
        .scopeFromProduction()
        .classes()
        .withNameEndingWith("UseCase")
        .assertTrue { it.hasTestClasses() }
}
PreviousArchitecture SnippetsNextKotlin Serialization Snippets

Last updated 8 months ago

🔍