From 4add26ff52efc0eede8931853289eb3dadd1c26e Mon Sep 17 00:00:00 2001 From: XXNitram Date: Tue, 10 Mar 2020 16:36:00 +0100 Subject: [PATCH 1/5] Rename ArchUnitTest to LayeredArchitectureTest and define/test a layered Architecture --- .../gruppen2/architecture/ArchUnitTest.java | 91 ------------------- .../architecture/LayeredArchitectureTest.java | 39 ++++++++ 2 files changed, 39 insertions(+), 91 deletions(-) delete mode 100644 src/test/java/mops/gruppen2/architecture/ArchUnitTest.java create mode 100644 src/test/java/mops/gruppen2/architecture/LayeredArchitectureTest.java diff --git a/src/test/java/mops/gruppen2/architecture/ArchUnitTest.java b/src/test/java/mops/gruppen2/architecture/ArchUnitTest.java deleted file mode 100644 index 2d0b315..0000000 --- a/src/test/java/mops/gruppen2/architecture/ArchUnitTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package mops.gruppen2.architecture; - -import com.tngtech.archunit.junit.AnalyzeClasses; -import com.tngtech.archunit.junit.ArchIgnore; -import com.tngtech.archunit.junit.ArchTest; -import com.tngtech.archunit.lang.ArchRule; -import org.springframework.data.repository.CrudRepository; -import org.springframework.stereotype.Controller; -import org.springframework.stereotype.Service; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; -import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; - -@AnalyzeClasses(packages = "mops.gruppen2") -public class ArchUnitTest { - - @ArchTest - public static final ArchRule controllerClassesShouldBeAnnotatedWithControllerOrRestControllerAnnotation = classes() - .that().haveSimpleNameEndingWith("Controller") - .should().beAnnotatedWith(Controller.class) - .orShould().beAnnotatedWith(RestController.class); - - @ArchTest - public static final ArchRule controllerClassesShouldHaveControllerInName = classes() - .that().areAnnotatedWith(Controller.class) - .or().areAnnotatedWith(RestController.class) - .should().haveSimpleNameEndingWith("Controller"); - - @ArchTest - public static final ArchRule controllerClassesShouldBeInControllerPackage = classes() - .that().areAnnotatedWith(Controller.class) - .or().areAnnotatedWith(RestController.class) - .should().resideInAPackage("..controller.."); - - @ArchTest - public static final ArchRule noClassesWithControllerOrRestControllerAnnotationShouldResideOutsideOfControllerPackage = noClasses() - .that().areAnnotatedWith(Controller.class) - .or().areAnnotatedWith(RestController.class) - .should().resideOutsideOfPackage("..controller.."); - - @ArchTest - public static final ArchRule controllerClassesShouldHaveRequestMappingAnnotation = classes() - .that().resideInAPackage("..controller..") - .and().haveSimpleNameEndingWith("Controller") - .and().areAnnotatedWith(Controller.class) - .or().areAnnotatedWith(RestController.class) - .should().beAnnotatedWith(RequestMapping.class); - - @ArchTest - public static final ArchRule controllerClassesShouldNotDependOnEachOther = noClasses() - .that().haveSimpleNameEndingWith("Controller") - .should().dependOnClassesThat().haveNameMatching("Controller"); - - @ArchTest - public static final ArchRule serviceClassesShouldHaveServiceInName = classes() - .that().areAnnotatedWith(Service.class) - .should().haveSimpleNameEndingWith("Service"); - - @ArchTest - public static final ArchRule serviceClassesShouldBeAnnotatedWithService = classes() - .that().haveSimpleNameEndingWith("Service") - .should().beAnnotatedWith(Service.class); - - @ArchTest - public static final ArchRule serviceClassesShouldBeInServicePackage = classes() - .that().areAnnotatedWith(Service.class) - .should().resideInAPackage("..service.."); - - @ArchTest - public static final ArchRule serviceClassesShouldOnlyBeAccessedByControllerOrServiceClasses = classes() - .that().resideInAPackage("..service..") - .should().onlyBeAccessed().byAnyPackage("..controller..", "..service.."); - - @ArchTest - public static final ArchRule domainClassesShouldNotAccessOtherClasses = noClasses() - .that().resideInAPackage("..domain..") - .should().accessClassesThat().resideInAnyPackage("..controller..", "..repository..", "..security..", "..service.."); - - @ArchTest - public static final ArchRule repositoryClassesThatImplementCrudRepositoryShouldBeNamedRepository = classes() - .that().implement(CrudRepository.class) - .should().haveSimpleNameEndingWith("Repository"); - - @ArchTest - public static final ArchRule repositoryClassesShouldBeInRepositoryPackage = classes() - .that().haveSimpleNameEndingWith("Repository") - .should().resideInAPackage("..repository.."); - -} diff --git a/src/test/java/mops/gruppen2/architecture/LayeredArchitectureTest.java b/src/test/java/mops/gruppen2/architecture/LayeredArchitectureTest.java new file mode 100644 index 0000000..f4c7b97 --- /dev/null +++ b/src/test/java/mops/gruppen2/architecture/LayeredArchitectureTest.java @@ -0,0 +1,39 @@ +package mops.gruppen2.architecture; + + import com.tngtech.archunit.core.importer.ImportOption; + import com.tngtech.archunit.junit.AnalyzeClasses; + import com.tngtech.archunit.junit.ArchTest; + import com.tngtech.archunit.lang.ArchRule; + import com.tngtech.archunit.library.Architectures; + +@AnalyzeClasses(packages = "mops.gruppen2", importOptions = { ImportOption.DoNotIncludeTests.class }) +public class LayeredArchitectureTest { + + private static Architectures.LayeredArchitecture layeredArchitecture = Architectures + .layeredArchitecture() + .layer("Domain").definedBy("..domain..") + .layer("Service").definedBy("..service") + .layer("Controller").definedBy("..controller..") + .layer("Repository").definedBy("..repository.."); + + @ArchTest + public static final ArchRule domainLayerShouldOnlyBeAccessedByServiceAndControllerLayer = layeredArchitecture + .whereLayer("Domain") + .mayOnlyBeAccessedByLayers("Service", "Controller"); + + @ArchTest + public static final ArchRule serviceLayerShouldOnlyBeAccessedByControllerLayer = layeredArchitecture + .whereLayer("Service") + .mayOnlyBeAccessedByLayers("Controller"); + + @ArchTest + public static final ArchRule repositoryLayerShouldOnlyBeAccessedByServiceLayer = layeredArchitecture + .whereLayer("Repository") + .mayOnlyBeAccessedByLayers("Service"); + + @ArchTest + public static final ArchRule controllerLayerShouldNotBeAccessedByAnyLayer = layeredArchitecture + .whereLayer("Controller") + .mayNotBeAccessedByAnyLayer(); + +} From 05218e8167e6ffb3f666b9ea8b32bdb9c4659526 Mon Sep 17 00:00:00 2001 From: XXNitram Date: Tue, 10 Mar 2020 16:41:05 +0100 Subject: [PATCH 2/5] Separate Tests into different classes, starting with ControllerTest --- .../gruppen2/architecture/ControllerTest.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/test/java/mops/gruppen2/architecture/ControllerTest.java diff --git a/src/test/java/mops/gruppen2/architecture/ControllerTest.java b/src/test/java/mops/gruppen2/architecture/ControllerTest.java new file mode 100644 index 0000000..8079fa8 --- /dev/null +++ b/src/test/java/mops/gruppen2/architecture/ControllerTest.java @@ -0,0 +1,53 @@ +package mops.gruppen2.architecture; + +import com.tngtech.archunit.core.importer.ImportOption; +import com.tngtech.archunit.junit.AnalyzeClasses; +import com.tngtech.archunit.junit.ArchTest; +import com.tngtech.archunit.lang.ArchRule; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; + +@AnalyzeClasses(packages = "mops.gruppen2", importOptions = { ImportOption.DoNotIncludeTests.class }) +public class ControllerTest { + + @ArchTest + public static final ArchRule controllerClassesShouldBeAnnotatedWithControllerOrRestControllerAnnotation = classes() + .that().haveSimpleNameEndingWith("Controller") + .should().beAnnotatedWith(Controller.class) + .orShould().beAnnotatedWith(RestController.class); + + @ArchTest + public static final ArchRule controllerClassesShouldHaveControllerInName = classes() + .that().areAnnotatedWith(Controller.class) + .or().areAnnotatedWith(RestController.class) + .should().haveSimpleNameEndingWith("Controller"); + + @ArchTest + public static final ArchRule controllerClassesShouldBeInControllerPackage = classes() + .that().areAnnotatedWith(Controller.class) + .or().areAnnotatedWith(RestController.class) + .should().resideInAPackage("..controller.."); + + @ArchTest + public static final ArchRule classesInControllerPackageShouldHaveControllerInName = classes() + .that().resideInAPackage("..controller..") + .should().haveSimpleNameEndingWith("Controller"); + + @ArchTest + public static final ArchRule controllerClassesShouldHaveRequestMappingAnnotation = classes() + .that().resideInAPackage("..controller..") + .and().haveSimpleNameEndingWith("Controller") + .and().areAnnotatedWith(Controller.class) + .or().areAnnotatedWith(RestController.class) + .should().beAnnotatedWith(RequestMapping.class); + + @ArchTest + public static final ArchRule controllerClassesShouldNotDependOnEachOther = noClasses() + .that().haveSimpleNameEndingWith("Controller") + .should().dependOnClassesThat().haveNameMatching("Controller"); + +} From fba7136d5738e7921a2ca214cde8cd4a30580b29 Mon Sep 17 00:00:00 2001 From: XXNitram Date: Tue, 10 Mar 2020 16:43:25 +0100 Subject: [PATCH 3/5] Add Tests for Repository and add Repository Annotation in EventRepository --- .../gruppen2/repository/EventRepository.java | 2 + .../gruppen2/architecture/RepositoryTest.java | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/test/java/mops/gruppen2/architecture/RepositoryTest.java diff --git a/src/main/java/mops/gruppen2/repository/EventRepository.java b/src/main/java/mops/gruppen2/repository/EventRepository.java index c4b1249..bb9947b 100644 --- a/src/main/java/mops/gruppen2/repository/EventRepository.java +++ b/src/main/java/mops/gruppen2/repository/EventRepository.java @@ -2,6 +2,8 @@ package mops.gruppen2.repository; import mops.gruppen2.domain.EventDTO; import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; +@Repository public interface EventRepository extends CrudRepository { } diff --git a/src/test/java/mops/gruppen2/architecture/RepositoryTest.java b/src/test/java/mops/gruppen2/architecture/RepositoryTest.java new file mode 100644 index 0000000..81f86ee --- /dev/null +++ b/src/test/java/mops/gruppen2/architecture/RepositoryTest.java @@ -0,0 +1,40 @@ +package mops.gruppen2.architecture; + +import com.tngtech.archunit.core.importer.ImportOption; +import com.tngtech.archunit.junit.AnalyzeClasses; +import com.tngtech.archunit.junit.ArchTest; +import com.tngtech.archunit.lang.ArchRule; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; + +@AnalyzeClasses(packages = "mops.gruppen2", importOptions = { ImportOption.DoNotIncludeTests.class }) +public class RepositoryTest { + + @ArchTest + public static final ArchRule repositoryClassesThatAreAnnotatedWithRepositoryShouldHaveRepositoryInName = classes() + .that().areAnnotatedWith(Repository.class) + .should().haveSimpleNameEndingWith("Repository"); + + @ArchTest + public static final ArchRule repositoryClassesShouldBeInRepositoryPackage = classes() + .that().haveSimpleNameEndingWith("Repository") + .should().resideInAPackage("..repository.."); + + @ArchTest + public static final ArchRule repositoryClassesShouldBeAnnotatedWithRepositoryAnnotation = classes() + .that().haveSimpleNameEndingWith("Repository") + .should().beAnnotatedWith(Repository.class); + + @ArchTest + public static final ArchRule classesInRepositoryPackageShouldHaveRepositoryInName = classes() + .that().resideInAPackage("..repository..") + .should().haveSimpleNameEndingWith("Repository"); + + @ArchTest + public static final ArchRule classesThatAreAssignableToCrudRepositoryShouldHaveRepositoryInName = classes() + .that().areAssignableTo(CrudRepository.class) + .should().beAnnotatedWith(Repository.class); + +} From 7dc1414e76033089f4cbe06c1d1f8b9ebb51b384 Mon Sep 17 00:00:00 2001 From: XXNitram Date: Tue, 10 Mar 2020 16:44:15 +0100 Subject: [PATCH 4/5] Add tests for Domain Architecture in DomainTest --- .../gruppen2/architecture/DomainTest.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/test/java/mops/gruppen2/architecture/DomainTest.java diff --git a/src/test/java/mops/gruppen2/architecture/DomainTest.java b/src/test/java/mops/gruppen2/architecture/DomainTest.java new file mode 100644 index 0000000..7340f80 --- /dev/null +++ b/src/test/java/mops/gruppen2/architecture/DomainTest.java @@ -0,0 +1,50 @@ +package mops.gruppen2.architecture; + +import com.tngtech.archunit.core.importer.ImportOption; +import com.tngtech.archunit.junit.AnalyzeClasses; +import com.tngtech.archunit.junit.ArchIgnore; +import com.tngtech.archunit.junit.ArchTest; +import com.tngtech.archunit.lang.ArchRule; + +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; + +@AnalyzeClasses(packages = "mops.gruppen2", importOptions = { ImportOption.DoNotIncludeTests.class }) +public class DomainTest { + + @ArchTest + public static final ArchRule domainClassesShouldNotAccessClassesFromOtherPackagesExceptDomainItself = noClasses() + .that().resideInAPackage("..domain..") + .should().accessClassesThat().resideInAnyPackage("..controller..", "..repository..", "..security..", "..service.."); + + @ArchTest + public static final ArchRule eventClassesShouldBeInEventPackage = classes() + .that().haveSimpleNameEndingWith("Event") + .should().resideInAPackage("..domain.event.."); + + @ArchTest + public static final ArchRule classesInEventPackageShouldHaveEventInName = classes() + .that().resideInAPackage("..domain.event..") + .should().haveSimpleNameEndingWith("Event"); + + @ArchTest + public static final ArchRule exceptionClassesShouldBeInExceptionPackage = classes() + .that().haveSimpleNameEndingWith("Exception") + .should().resideInAPackage("..domain.Exceptions.."); + + @ArchTest + public static final ArchRule classesInExceptionPackageShouldHaveExceptionInName = classes() + .that().resideInAPackage("..domain.Exceptions..") + .should().haveSimpleNameEndingWith("Exception"); + + @ArchTest + public static final ArchRule classesThatAreAssignableToExceptionShouldHaveExceptionInName = classes() + .that().areAssignableTo(Exception.class) + .should().haveSimpleNameEndingWith("Exception"); + + @ArchTest + public static final ArchRule classesThatHaveExceptionInNameShouldBeAssignableToExceptionClass = classes() + .that().haveSimpleNameEndingWith("Exception") + .should().beAssignableTo(Exception.class); + +} From 4f619c6963b5cc0e257e395132d4a531b568f461 Mon Sep 17 00:00:00 2001 From: XXNitram Date: Tue, 10 Mar 2020 16:44:58 +0100 Subject: [PATCH 5/5] Add tests for Service Architecture in ServiceTest --- .../gruppen2/architecture/ServiceTest.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/test/java/mops/gruppen2/architecture/ServiceTest.java diff --git a/src/test/java/mops/gruppen2/architecture/ServiceTest.java b/src/test/java/mops/gruppen2/architecture/ServiceTest.java new file mode 100644 index 0000000..514ffa2 --- /dev/null +++ b/src/test/java/mops/gruppen2/architecture/ServiceTest.java @@ -0,0 +1,39 @@ +package mops.gruppen2.architecture; + +import com.tngtech.archunit.core.importer.ImportOption; +import com.tngtech.archunit.junit.AnalyzeClasses; +import com.tngtech.archunit.junit.ArchTest; +import com.tngtech.archunit.lang.ArchRule; +import org.springframework.stereotype.Service; + +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; + +@AnalyzeClasses(packages = "mops.gruppen2", importOptions = { ImportOption.DoNotIncludeTests.class }) +public class ServiceTest { + + @ArchTest + public static final ArchRule serviceClassesShouldHaveServiceInName = classes() + .that().areAnnotatedWith(Service.class) + .should().haveSimpleNameEndingWith("Service"); + + @ArchTest + public static final ArchRule serviceClassesShouldBeAnnotatedWithService = classes() + .that().haveSimpleNameEndingWith("Service") + .should().beAnnotatedWith(Service.class); + + @ArchTest + public static final ArchRule serviceClassesShouldBeInServicePackage = classes() + .that().areAnnotatedWith(Service.class) + .should().resideInAPackage("..service.."); + + @ArchTest + public static final ArchRule classesInServicePackageShouldHaveServiceInName = classes() + .that().resideInAPackage("..service..") + .should().haveSimpleNameEndingWith("Service"); + + @ArchTest + public static final ArchRule serviceClassesShouldOnlyBeAccessedByControllerOrServiceClasses = classes() + .that().resideInAPackage("..service..") + .should().onlyBeAccessed().byAnyPackage("..controller..", "..service.."); + +}