From 4ebb195f2e3b63c3f17a6ee7e71c3388fb9e1799 Mon Sep 17 00:00:00 2001 From: Carsten Otto Date: Tue, 30 Nov 2021 17:07:13 +0100 Subject: [PATCH] add archunit tests --- .../java/de/cotto/lndmanagej/ArchUnitIT.java | 86 +++++++++++++++++++ .../lndmanagej/controller/ArchUnitIT.java | 49 +++++++++++ 2 files changed, 135 insertions(+) create mode 100644 application/src/integrationTest/java/de/cotto/lndmanagej/ArchUnitIT.java create mode 100644 web/src/integrationTest/java/de/cotto/lndmanagej/controller/ArchUnitIT.java diff --git a/application/src/integrationTest/java/de/cotto/lndmanagej/ArchUnitIT.java b/application/src/integrationTest/java/de/cotto/lndmanagej/ArchUnitIT.java new file mode 100644 index 00000000..aabb7d93 --- /dev/null +++ b/application/src/integrationTest/java/de/cotto/lndmanagej/ArchUnitIT.java @@ -0,0 +1,86 @@ +package de.cotto.lndmanagej; + +import com.codahale.metrics.annotation.Timed; +import com.tngtech.archunit.core.domain.JavaClasses; +import com.tngtech.archunit.core.importer.ClassFileImporter; +import com.tngtech.archunit.core.importer.ImportOption; +import com.tngtech.archunit.core.importer.Location; +import com.tngtech.archunit.lang.ArchRule; +import com.tngtech.archunit.lang.syntax.ArchRuleDefinition; +import com.tngtech.archunit.library.dependencies.SliceRule; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.regex.Pattern; + +import static com.tngtech.archunit.library.dependencies.SlicesRuleDefinition.slices; +import static org.assertj.core.api.Assertions.assertThat; + +class ArchUnitIT { + + private static JavaClasses importedClasses; + + @BeforeAll + static void setUp() { + importedClasses = new ClassFileImporter().withImportOption(new DoNotIncludeTests()).importPackages("de.cotto"); + } + + @Test + void services_must_not_access_dto_classes_directly() { + ArchRule rule = ArchRuleDefinition.classes().that() + .haveSimpleNameEndingWith("Dto").or().haveSimpleNameEndingWith("DTO") + .should() + .onlyHaveDependentClassesThat().haveSimpleNameNotEndingWith("Service"); + assertThat(importedClasses).isNotEmpty(); + rule.check(importedClasses); + } + + @Test + void services_must_not_access_spring_data_repositories_directly() { + ArchRule rule = ArchRuleDefinition.classes().that() + .areAssignableTo("org.springframework.data.repository.Repository.class") + .should() + .onlyHaveDependentClassesThat().haveSimpleNameNotEndingWith("Service"); + assertThat(importedClasses).isNotEmpty(); + rule.check(importedClasses); + } + + @Test + void no_package_cycle() { + SliceRule rule = slices().matching("de.cotto.(**)").should().beFreeOfCycles(); + assertThat(importedClasses).isNotEmpty(); + rule.check(importedClasses); + } + + @Test + void daos_are_transactional() { + ArchRule rule = ArchRuleDefinition.classes().that() + .haveSimpleNameEndingWith("DaoImpl") + .should() + .beAnnotatedWith("javax.transaction.Transactional") + .orShould() + .beAnnotatedWith("org.springframework.transaction.annotation.Transactional"); + // https://stackoverflow.com/q/26387399/947526 + assertThat(importedClasses).isNotEmpty(); + rule.check(importedClasses); + } + + @Test + void timed_methods_are_public() { + ArchRule rule = ArchRuleDefinition.methods().that() + .areAnnotatedWith(Timed.class) + .should() + .bePublic(); + assertThat(importedClasses).isNotEmpty(); + rule.check(importedClasses); + } + + private static class DoNotIncludeTests implements ImportOption { + private static final Pattern GRADLE_PATTERN = Pattern.compile(".*/build/classes/([^/]+/)?[a-zA-Z-]*[tT]est/.*"); + + @Override + public boolean includes(Location location) { + return !location.matches(GRADLE_PATTERN); + } + } +} diff --git a/web/src/integrationTest/java/de/cotto/lndmanagej/controller/ArchUnitIT.java b/web/src/integrationTest/java/de/cotto/lndmanagej/controller/ArchUnitIT.java new file mode 100644 index 00000000..68077e7d --- /dev/null +++ b/web/src/integrationTest/java/de/cotto/lndmanagej/controller/ArchUnitIT.java @@ -0,0 +1,49 @@ +package de.cotto.lndmanagej.controller; + +import com.codahale.metrics.annotation.Timed; +import com.tngtech.archunit.core.domain.JavaClasses; +import com.tngtech.archunit.core.importer.ClassFileImporter; +import com.tngtech.archunit.core.importer.ImportOption; +import com.tngtech.archunit.core.importer.Location; +import com.tngtech.archunit.lang.ArchRule; +import com.tngtech.archunit.lang.syntax.ArchRuleDefinition; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.web.bind.annotation.RequestMapping; + +import java.util.regex.Pattern; + +import static org.assertj.core.api.Assertions.assertThat; + +class ArchUnitIT { + + private static JavaClasses importedClasses; + + @BeforeAll + static void setUp() { + importedClasses = new ClassFileImporter() + .withImportOption(new DoNotIncludeTests()) + .importPackages("de.cotto.lndmanagej.controller"); + } + + @Test + void public_controller_methods_are_timed() { + ArchRule rule = ArchRuleDefinition.methods().that() + .areDeclaredInClassesThat().areAnnotatedWith(RequestMapping.class) + .and() + .arePublic() + .should() + .beAnnotatedWith(Timed.class); + assertThat(importedClasses).isNotEmpty(); + rule.check(importedClasses); + } + + private static class DoNotIncludeTests implements ImportOption { + private static final Pattern GRADLE_PATTERN = Pattern.compile(".*/build/classes/([^/]+/)?[a-zA-Z-]*[tT]est/.*"); + + @Override + public boolean includes(Location location) { + return !location.matches(GRADLE_PATTERN); + } + } +}