From 6ac09612406ba45fed52e4eb9cd5cd757a506e91 Mon Sep 17 00:00:00 2001 From: DanielOber <145556033+DanielOber@users.noreply.github.com> Date: Fri, 12 Sep 2025 14:36:44 +0200 Subject: [PATCH 1/6] added archunit and fixed tests --- refarch-backend/pom.xml | 6 +++ .../refarch/archunit/ArchUnitTest.java | 42 +++++++++++++++++++ .../refarch/archunit/rules/MethodRules.java | 41 ++++++++++++++++++ .../TestClassesEndWithTestCondition.java | 37 ++++++++++++++++ .../filter/CacheControlFilterTest.java | 2 +- .../UnicodeFilterConfigurationTest.java | 2 +- .../filter/nfcconverter/NfcConverterTest.java | 4 +- .../filter/nfcconverter/NfcHelperTest.java | 12 +++--- ...KeycloakRolesAuthoritiesConverterTest.java | 8 ++-- .../UserInfoAuthoritiesConverterTest.java | 6 +-- 10 files changed, 143 insertions(+), 17 deletions(-) create mode 100644 refarch-backend/src/test/java/de/muenchen/refarch/archunit/ArchUnitTest.java create mode 100644 refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java create mode 100644 refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/TestClassesEndWithTestCondition.java diff --git a/refarch-backend/pom.xml b/refarch-backend/pom.xml index 5b78de35e..76ace2bc8 100644 --- a/refarch-backend/pom.xml +++ b/refarch-backend/pom.xml @@ -58,6 +58,7 @@ 0.8.13 + 1.4.1 3.1.1 @@ -259,6 +260,11 @@ spring-boot-configuration-processor true + + com.tngtech.archunit + archunit + ${archunit.version} + diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/ArchUnitTest.java b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/ArchUnitTest.java new file mode 100644 index 000000000..dd67bb627 --- /dev/null +++ b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/ArchUnitTest.java @@ -0,0 +1,42 @@ +package de.muenchen.refarch.archunit; + +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.lang.ArchRule; +import de.muenchen.refarch.archunit.rules.MethodRules; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.aggregator.ArgumentsAccessor; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class ArchUnitTest { + + private static JavaClasses allTestClasses; + + @BeforeAll + static void init() { + allTestClasses = new ClassFileImporter() + .withImportOption(new ImportOption.OnlyIncludeTests()) + .importPackages(de.muenchen.refarch.MicroServiceApplication.class.getPackage().getName()); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("allTestClassesRulesToVerify") + void givenAllArchUnitRulesForAllTestClasses_thenRunArchUnitTests(final ArgumentsAccessor arguments) { + arguments.get(1, ArchRule.class).check(allTestClasses); + } + + public static Stream allTestClassesRulesToVerify() { + return Stream.of( + Arguments.of("RULE_TESTCLASSES_END_WITH_TEST_CONVENTION_MATCHED", + MethodRules.RULE_TESTCLASSES_END_WITH_TEST_CONVENTION_MATCHED), + Arguments.of("TEST_NAMING_CONVENTION_RULE", MethodRules.RULE_TEST_NAMING_CONVENTION_SHOULD_WHEN_MATCHED), + Arguments.of("RULE_BEFORE_EACH_NAMING_CONVENTION_MATCHED", MethodRules.RULE_BEFORE_EACH_NAMING_CONVENTION_MATCHED), + Arguments.of("RULE_AFTER_EACH_NAMING_CONVENTION_MATCHED", MethodRules.RULE_AFTER_EACH_NAMING_CONVENTION_MATCHED), + Arguments.of("TEST_METHODS_ARE_PACKAGE_PRIVATE_CONVENTION_MATCHED", MethodRules.RULE_TEST_METHODS_ARE_PACKAGE_PRIVATE_CONVENTION_MATCHED)); + } + +} diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java new file mode 100644 index 000000000..e8172f7de --- /dev/null +++ b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java @@ -0,0 +1,41 @@ +package de.muenchen.refarch.archunit.rules; + +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.methods; +import static de.muenchen.refarch.archunit.rules.TestClassesEndWithTestCondition.haveTopEnclosingClassEndingWithTest; + +import com.tngtech.archunit.core.domain.JavaModifier; +import com.tngtech.archunit.lang.ArchRule; +import com.tngtech.archunit.lang.syntax.elements.MethodsShouldConjunction; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.springframework.web.bind.annotation.RequestMapping; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MethodRules { + + public static final MethodsShouldConjunction RULE_TEST_NAMING_CONVENTION_SHOULD_WHEN_MATCHED = methods() + .that().areAnnotatedWith(Test.class).or().areAnnotatedWith(ParameterizedTest.class) + .should().haveNameMatching("^given[A-Z][a-zA-Z]+_then[A-Z][a-zA-Z]+$$$$$"); + + public static final ArchRule RULE_BEFORE_EACH_NAMING_CONVENTION_MATCHED = methods() + .that().areAnnotatedWith(BeforeEach.class).should().haveNameMatching("setUp") + .allowEmptyShould(true); + + public static final ArchRule RULE_AFTER_EACH_NAMING_CONVENTION_MATCHED = methods() + .that().areAnnotatedWith(AfterEach.class).should().haveNameMatching("tearDown") + .allowEmptyShould(true); + + public static final ArchRule RULE_TEST_METHODS_ARE_PACKAGE_PRIVATE_CONVENTION_MATCHED = methods() + .that().areAnnotatedWith(Test.class).or().areAnnotatedWith(ParameterizedTest.class).should() + .notHaveModifier(JavaModifier.PROTECTED) + .andShould().notHaveModifier(JavaModifier.PRIVATE) + .andShould().notHaveModifier(JavaModifier.PUBLIC); + + public static final ArchRule RULE_TESTCLASSES_END_WITH_TEST_CONVENTION_MATCHED = methods() + .that().areAnnotatedWith(Test.class).or().areAnnotatedWith(ParameterizedTest.class) + .should(haveTopEnclosingClassEndingWithTest); +} diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/TestClassesEndWithTestCondition.java b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/TestClassesEndWithTestCondition.java new file mode 100644 index 000000000..a60faaeb5 --- /dev/null +++ b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/TestClassesEndWithTestCondition.java @@ -0,0 +1,37 @@ +package de.muenchen.refarch.archunit.rules; + +import com.tngtech.archunit.core.domain.JavaClass; +import com.tngtech.archunit.core.domain.JavaMethod; +import com.tngtech.archunit.lang.ArchCondition; +import com.tngtech.archunit.lang.ConditionEvents; +import com.tngtech.archunit.lang.SimpleConditionEvent; +import java.util.Optional; + +public class TestClassesEndWithTestCondition extends ArchCondition { + + TestClassesEndWithTestCondition() { + super("have top enclosing class name ending with `Test`"); + } + + public static final ArchCondition haveTopEnclosingClassEndingWithTest = new TestClassesEndWithTestCondition(); + + @Override + public void check(JavaMethod method, ConditionEvents events) { + var topEnclosingClass = getTopEnclosingClass(method.getOwner()); + + if (topEnclosingClass.isPresent() && !topEnclosingClass.get().getFullName().endsWith("Test")) { + events.add(SimpleConditionEvent.violated(method, "test " + method.getName() + " is not inside of test class")); + } + } + + private Optional getTopEnclosingClass(JavaClass item) { + JavaClass enclosingClass = null; + while (item.getEnclosingClass().isPresent()) { + item = item.getEnclosingClass().orElseThrow(); + enclosingClass = item; + } + + enclosingClass = enclosingClass == null ? item : enclosingClass; + return Optional.of(enclosingClass); + } +} diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/CacheControlFilterTest.java b/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/CacheControlFilterTest.java index fad824e4d..9c0bef952 100644 --- a/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/CacheControlFilterTest.java +++ b/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/CacheControlFilterTest.java @@ -44,7 +44,7 @@ class CacheControlFilterTest { private TestRestTemplate testRestTemplate; @Test - void testForCacheControlHeadersForEntityEndpoint() { + void givenEntityEndpoint_thenCacheControlHeadersPresent() { final ResponseEntity response = testRestTemplate.exchange(ENTITY_ENDPOINT_URL, HttpMethod.GET, null, String.class); assertEquals(HttpStatus.OK, response.getStatusCode()); assertTrue(response.getHeaders().containsKey(HttpHeaders.CACHE_CONTROL)); diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/UnicodeFilterConfigurationTest.java b/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/UnicodeFilterConfigurationTest.java index ba3cea914..fb7fd0b4e 100644 --- a/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/UnicodeFilterConfigurationTest.java +++ b/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/UnicodeFilterConfigurationTest.java @@ -58,7 +58,7 @@ class UnicodeFilterConfigurationTest { private TheEntityRepository theEntityRepository; @Test - void testForNfcNormalization() { + void givenDecomposedString_thenCovertToNfcNormalized() { // Given // Persist entity with decomposed string. final TheEntityRequestDTO theEntityRequestDto = new TheEntityRequestDTO(TEXT_ATTRIBUTE_DECOMPOSED); diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/nfcconverter/NfcConverterTest.java b/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/nfcconverter/NfcConverterTest.java index e0ec0a0d4..5025bcff6 100644 --- a/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/nfcconverter/NfcConverterTest.java +++ b/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/nfcconverter/NfcConverterTest.java @@ -70,7 +70,7 @@ class NfcConverterTest { // Test that request with configured ContentType is normalized to NFC. @Test - void testFilterIfContenttypeInWhitelist() throws ServletException, IOException { + void givenContenttypeInWhitelist_thenFilter() throws ServletException, IOException { mockRequest("text/plain"); filter.doFilter(req, resp, chain); @@ -90,7 +90,7 @@ void testFilterIfContenttypeInWhitelist() throws ServletException, IOException { // Test that Request not configured ContentType remains unchanged, i.e. is not normalized to NFC. @Test - void testSkipFilterIfContenttypeNotInWhitelist() throws ServletException, IOException { + void givenContenttypeNotInWhitelist_thenSkipFilter() throws ServletException, IOException { mockRequest("application/notvalid"); filter.doFilter(req, resp, chain); diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/nfcconverter/NfcHelperTest.java b/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/nfcconverter/NfcHelperTest.java index 9c13e92a5..22aa1d327 100644 --- a/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/nfcconverter/NfcHelperTest.java +++ b/refarch-backend/src/test/java/de/muenchen/refarch/configuration/filter/nfcconverter/NfcHelperTest.java @@ -29,7 +29,7 @@ class NfcHelperTest { private static final String[] NFC_OUTPUT_EXPECTED = { FIRST_NFC, SECOND_NFC, THIRD_NFC }; @Test - void nfcConverterString() { + void givenString_thenNfcConverted() { assertEquals(FIRST_NFC, NfcHelper.nfcConverter(FIRST_NFD)); assertEquals(FIRST_NFC.length(), NfcHelper.nfcConverter(FIRST_NFD).length()); @@ -41,7 +41,7 @@ void nfcConverterString() { } @Test - void nfcConverterStringBuffer() { + void givenStringBuffer_thenNfcConverted() { assertEquals(FIRST_NFC, NfcHelper.nfcConverter(new StringBuffer(FIRST_NFD)).toString()); assertEquals(FIRST_NFC.length(), NfcHelper.nfcConverter(new StringBuffer(FIRST_NFD)).length()); @@ -53,13 +53,13 @@ void nfcConverterStringBuffer() { } @Test - void nfcConverterStringArray() { + void givenStringArray_thenNfcConverted() { assertArrayEquals(NFC_OUTPUT_EXPECTED, NfcHelper.nfcConverter(NFD_INPUT)); assertEquals(NFC_OUTPUT_EXPECTED.length, NfcHelper.nfcConverter(NFD_INPUT).length); } @Test - void nfcConverterMapOfStrings() { + void givenMapOfStrings_thenNfcConverted() { final Map nfdInput = new HashMap<>(); nfdInput.put(FIRST_NFD, NFD_INPUT); nfdInput.put(SECOND_NFD, NFD_INPUT); @@ -73,7 +73,7 @@ void nfcConverterMapOfStrings() { } @Test - void nfcConverterCookie() { + void givenCookie_thenNfcConverted() { final Cookie nfcCookie = NfcHelper.nfcConverter(createNfdCookie()); assertEquals(NfcConverterTest.TOKEN, nfcCookie.getName()); @@ -84,7 +84,7 @@ void nfcConverterCookie() { @SuppressWarnings("PMD.UnitTestShouldIncludeAssert") @Test - void nfcConverterCookieArray() { + void givenCookieArray_thenNfcConverted() { final Cookie[] nfdCookies = Collections.nCopies(3, createNfdCookie()).toArray(new Cookie[3]); final Cookie[] nfcCookies = NfcHelper.nfcConverter(nfdCookies); Arrays.asList(nfcCookies).forEach(nfcCookie -> { diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/configuration/security/KeycloakRolesAuthoritiesConverterTest.java b/refarch-backend/src/test/java/de/muenchen/refarch/configuration/security/KeycloakRolesAuthoritiesConverterTest.java index a3a00ba75..5ec646282 100644 --- a/refarch-backend/src/test/java/de/muenchen/refarch/configuration/security/KeycloakRolesAuthoritiesConverterTest.java +++ b/refarch-backend/src/test/java/de/muenchen/refarch/configuration/security/KeycloakRolesAuthoritiesConverterTest.java @@ -36,7 +36,7 @@ void setUp() { } @Test - void testConvert_WithRoles() { + void givenRoles_thenConvert() { // Setup final Map resourceAccessClaim = new HashMap<>(); resourceAccessClaim.put(TEST_CLIENT, Map.of("roles", List.of("admin", "user"))); @@ -54,7 +54,7 @@ void testConvert_WithRoles() { } @Test - void testConvert_WithoutRoles() { + void givenNoRoles_thenConvert() { // Setup final Map claims = new HashMap<>(); claims.put(RESOURCE_ACCESS_CLAIM, Map.of( @@ -71,7 +71,7 @@ void testConvert_WithoutRoles() { } @Test - void testConvert_ClientNotInResourceAccess() { + void givenClientNotInResourceAccess_thenConvert() { // Setup final Map resourceAccessClaim = new HashMap<>(); resourceAccessClaim.put("other-client", Map.of("roles", List.of("admin"))); @@ -87,7 +87,7 @@ void testConvert_ClientNotInResourceAccess() { } @Test - void testConvert_NullClaims() { + void givenNullClaims_thenConvert() { // Setup final Jwt jwt = mock(Jwt.class); diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/configuration/security/UserInfoAuthoritiesConverterTest.java b/refarch-backend/src/test/java/de/muenchen/refarch/configuration/security/UserInfoAuthoritiesConverterTest.java index fb718fdb4..11f0e7c47 100644 --- a/refarch-backend/src/test/java/de/muenchen/refarch/configuration/security/UserInfoAuthoritiesConverterTest.java +++ b/refarch-backend/src/test/java/de/muenchen/refarch/configuration/security/UserInfoAuthoritiesConverterTest.java @@ -48,7 +48,7 @@ void setUp() { } @Test - void testConvert_WithAuthorities() { + void givenNoRoles_thenConvert() { // Setup final Jwt jwt = mock(Jwt.class); when(jwt.getSubject()).thenReturn(TEST_SUBJECT); @@ -70,7 +70,7 @@ void testConvert_WithAuthorities() { } @Test - void testConvert_NoAuthorities() { + void givenNoAuthorities_thenConvert() { // Setup final Jwt jwt = mock(Jwt.class); when(jwt.getSubject()).thenReturn(TEST_SUBJECT); @@ -89,7 +89,7 @@ void testConvert_NoAuthorities() { } @Test - void testConvert_CacheHit() { + void givenCacheHit_thenConvert() { // Setup final Jwt jwt = mock(Jwt.class); when(jwt.getSubject()).thenReturn(TEST_SUBJECT); From 8bcf652a9e0bf8c057a769e5556ea79cd61d671f Mon Sep 17 00:00:00 2001 From: DanielOber <145556033+DanielOber@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:05:59 +0200 Subject: [PATCH 2/6] spotless --- .../java/de/muenchen/refarch/archunit/rules/MethodRules.java | 1 - 1 file changed, 1 deletion(-) diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java index e8172f7de..f1cf860c2 100644 --- a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java +++ b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java @@ -12,7 +12,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; -import org.springframework.web.bind.annotation.RequestMapping; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class MethodRules { From 41d5b5cd8ece972da7e030d51d899da0efb55616 Mon Sep 17 00:00:00 2001 From: DanielOber <145556033+DanielOber@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:34:51 +0200 Subject: [PATCH 3/6] code rabbit review --- refarch-backend/pom.xml | 1 + .../refarch/archunit/rules/MethodRules.java | 4 ++-- .../rules/TestClassesEndWithTestCondition.java | 14 +++++--------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/refarch-backend/pom.xml b/refarch-backend/pom.xml index 76ace2bc8..85c2efee7 100644 --- a/refarch-backend/pom.xml +++ b/refarch-backend/pom.xml @@ -264,6 +264,7 @@ com.tngtech.archunit archunit ${archunit.version} + test diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java index f1cf860c2..1d601b2a3 100644 --- a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java +++ b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java @@ -14,11 +14,11 @@ import org.junit.jupiter.params.ParameterizedTest; @NoArgsConstructor(access = AccessLevel.PRIVATE) -public class MethodRules { +public final class MethodRules { public static final MethodsShouldConjunction RULE_TEST_NAMING_CONVENTION_SHOULD_WHEN_MATCHED = methods() .that().areAnnotatedWith(Test.class).or().areAnnotatedWith(ParameterizedTest.class) - .should().haveNameMatching("^given[A-Z][a-zA-Z]+_then[A-Z][a-zA-Z]+$$$$$"); + .should().haveNameMatching("^given[A-Z][a-zA-Z]+_then[A-Z][a-zA-Z]+$"); public static final ArchRule RULE_BEFORE_EACH_NAMING_CONVENTION_MATCHED = methods() .that().areAnnotatedWith(BeforeEach.class).should().haveNameMatching("setUp") diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/TestClassesEndWithTestCondition.java b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/TestClassesEndWithTestCondition.java index a60faaeb5..5703a72ba 100644 --- a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/TestClassesEndWithTestCondition.java +++ b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/TestClassesEndWithTestCondition.java @@ -5,7 +5,6 @@ import com.tngtech.archunit.lang.ArchCondition; import com.tngtech.archunit.lang.ConditionEvents; import com.tngtech.archunit.lang.SimpleConditionEvent; -import java.util.Optional; public class TestClassesEndWithTestCondition extends ArchCondition { @@ -19,19 +18,16 @@ public class TestClassesEndWithTestCondition extends ArchCondition { public void check(JavaMethod method, ConditionEvents events) { var topEnclosingClass = getTopEnclosingClass(method.getOwner()); - if (topEnclosingClass.isPresent() && !topEnclosingClass.get().getFullName().endsWith("Test")) { - events.add(SimpleConditionEvent.violated(method, "test " + method.getName() + " is not inside of test class")); + if (!topEnclosingClass.getName().endsWith("Test")) { + events.add(SimpleConditionEvent.violated(method, "Method %s must be declared in a class whose simple name ends with 'Test' (found: %s)" + .formatted(method.getName(), topEnclosingClass.getSimpleName()))); } } - private Optional getTopEnclosingClass(JavaClass item) { - JavaClass enclosingClass = null; + private JavaClass getTopEnclosingClass(JavaClass item) { while (item.getEnclosingClass().isPresent()) { item = item.getEnclosingClass().orElseThrow(); - enclosingClass = item; } - - enclosingClass = enclosingClass == null ? item : enclosingClass; - return Optional.of(enclosingClass); + return item; } } From 6ba6a2bec50208a80376d9285aa4e1b28d1a396e Mon Sep 17 00:00:00 2001 From: DanielOber <145556033+DanielOber@users.noreply.github.com> Date: Mon, 15 Sep 2025 16:22:52 +0200 Subject: [PATCH 4/6] code rabbit review --- .../java/de/muenchen/refarch/archunit/rules/MethodRules.java | 3 +-- .../archunit/rules/TestClassesEndWithTestCondition.java | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java index 1d601b2a3..ad9123b57 100644 --- a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java +++ b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java @@ -5,7 +5,6 @@ import com.tngtech.archunit.core.domain.JavaModifier; import com.tngtech.archunit.lang.ArchRule; -import com.tngtech.archunit.lang.syntax.elements.MethodsShouldConjunction; import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.junit.jupiter.api.AfterEach; @@ -16,7 +15,7 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public final class MethodRules { - public static final MethodsShouldConjunction RULE_TEST_NAMING_CONVENTION_SHOULD_WHEN_MATCHED = methods() + public static final ArchRule RULE_TEST_NAMING_CONVENTION_SHOULD_WHEN_MATCHED = methods() .that().areAnnotatedWith(Test.class).or().areAnnotatedWith(ParameterizedTest.class) .should().haveNameMatching("^given[A-Z][a-zA-Z]+_then[A-Z][a-zA-Z]+$"); diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/TestClassesEndWithTestCondition.java b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/TestClassesEndWithTestCondition.java index 5703a72ba..a6975fdfb 100644 --- a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/TestClassesEndWithTestCondition.java +++ b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/TestClassesEndWithTestCondition.java @@ -16,9 +16,9 @@ public class TestClassesEndWithTestCondition extends ArchCondition { @Override public void check(JavaMethod method, ConditionEvents events) { - var topEnclosingClass = getTopEnclosingClass(method.getOwner()); + final var topEnclosingClass = getTopEnclosingClass(method.getOwner()); - if (!topEnclosingClass.getName().endsWith("Test")) { + if (!topEnclosingClass.getSimpleName().endsWith("Test")) { events.add(SimpleConditionEvent.violated(method, "Method %s must be declared in a class whose simple name ends with 'Test' (found: %s)" .formatted(method.getName(), topEnclosingClass.getSimpleName()))); } From 564bca9c0f7be56bde396c46329e738f41cbe5fa Mon Sep 17 00:00:00 2001 From: DanielOber <145556033+DanielOber@users.noreply.github.com> Date: Thu, 18 Sep 2025 15:24:11 +0200 Subject: [PATCH 5/6] renaming --- .../de/muenchen/refarch/archunit/ArchUnitTest.java | 12 ++++++------ .../archunit/rules/{MethodRules.java => Rules.java} | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) rename refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/{MethodRules.java => Rules.java} (93%) diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/ArchUnitTest.java b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/ArchUnitTest.java index dd67bb627..88c63b195 100644 --- a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/ArchUnitTest.java +++ b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/ArchUnitTest.java @@ -4,7 +4,7 @@ import com.tngtech.archunit.core.importer.ClassFileImporter; import com.tngtech.archunit.core.importer.ImportOption; import com.tngtech.archunit.lang.ArchRule; -import de.muenchen.refarch.archunit.rules.MethodRules; +import de.muenchen.refarch.archunit.rules.Rules; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -32,11 +32,11 @@ void givenAllArchUnitRulesForAllTestClasses_thenRunArchUnitTests(final Arguments public static Stream allTestClassesRulesToVerify() { return Stream.of( Arguments.of("RULE_TESTCLASSES_END_WITH_TEST_CONVENTION_MATCHED", - MethodRules.RULE_TESTCLASSES_END_WITH_TEST_CONVENTION_MATCHED), - Arguments.of("TEST_NAMING_CONVENTION_RULE", MethodRules.RULE_TEST_NAMING_CONVENTION_SHOULD_WHEN_MATCHED), - Arguments.of("RULE_BEFORE_EACH_NAMING_CONVENTION_MATCHED", MethodRules.RULE_BEFORE_EACH_NAMING_CONVENTION_MATCHED), - Arguments.of("RULE_AFTER_EACH_NAMING_CONVENTION_MATCHED", MethodRules.RULE_AFTER_EACH_NAMING_CONVENTION_MATCHED), - Arguments.of("TEST_METHODS_ARE_PACKAGE_PRIVATE_CONVENTION_MATCHED", MethodRules.RULE_TEST_METHODS_ARE_PACKAGE_PRIVATE_CONVENTION_MATCHED)); + Rules.RULE_TESTCLASSES_END_WITH_TEST_CONVENTION_MATCHED), + Arguments.of("TEST_NAMING_CONVENTION_RULE", Rules.RULE_TEST_NAMING_CONVENTION_GIVEN_THEN_MATCHED), + Arguments.of("RULE_BEFORE_EACH_NAMING_CONVENTION_MATCHED", Rules.RULE_BEFORE_EACH_NAMING_CONVENTION_MATCHED), + Arguments.of("RULE_AFTER_EACH_NAMING_CONVENTION_MATCHED", Rules.RULE_AFTER_EACH_NAMING_CONVENTION_MATCHED), + Arguments.of("TEST_METHODS_ARE_PACKAGE_PRIVATE_CONVENTION_MATCHED", Rules.RULE_TEST_METHODS_ARE_PACKAGE_PRIVATE_CONVENTION_MATCHED)); } } diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/Rules.java similarity index 93% rename from refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java rename to refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/Rules.java index ad9123b57..849db8182 100644 --- a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/MethodRules.java +++ b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/Rules.java @@ -13,9 +13,9 @@ import org.junit.jupiter.params.ParameterizedTest; @NoArgsConstructor(access = AccessLevel.PRIVATE) -public final class MethodRules { +public final class Rules { - public static final ArchRule RULE_TEST_NAMING_CONVENTION_SHOULD_WHEN_MATCHED = methods() + public static final ArchRule RULE_TEST_NAMING_CONVENTION_GIVEN_THEN_MATCHED = methods() .that().areAnnotatedWith(Test.class).or().areAnnotatedWith(ParameterizedTest.class) .should().haveNameMatching("^given[A-Z][a-zA-Z]+_then[A-Z][a-zA-Z]+$"); From 8cc94f3f18f8de95a232c7e5dd38ab55b3d16880 Mon Sep 17 00:00:00 2001 From: DanielOber <145556033+DanielOber@users.noreply.github.com> Date: Fri, 10 Oct 2025 13:32:54 +0200 Subject: [PATCH 6/6] coderabbit review eingearbeitet --- .../refarch/archunit/rules/Rules.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/Rules.java b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/Rules.java index 849db8182..713b9fb6b 100644 --- a/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/Rules.java +++ b/refarch-backend/src/test/java/de/muenchen/refarch/archunit/rules/Rules.java @@ -9,31 +9,43 @@ import lombok.NoArgsConstructor; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.params.ParameterizedTest; @NoArgsConstructor(access = AccessLevel.PRIVATE) public final class Rules { public static final ArchRule RULE_TEST_NAMING_CONVENTION_GIVEN_THEN_MATCHED = methods() - .that().areAnnotatedWith(Test.class).or().areAnnotatedWith(ParameterizedTest.class) + .that().areAnnotatedWith(Test.class) + .or().areAnnotatedWith(ParameterizedTest.class) + .or().areAnnotatedWith(RepeatedTest.class) + .or() + .areAnnotatedWith(TestTemplate.class) .should().haveNameMatching("^given[A-Z][a-zA-Z]+_then[A-Z][a-zA-Z]+$"); public static final ArchRule RULE_BEFORE_EACH_NAMING_CONVENTION_MATCHED = methods() - .that().areAnnotatedWith(BeforeEach.class).should().haveNameMatching("setUp") + .that().areAnnotatedWith(BeforeEach.class).should().haveNameMatching("^setUp$") .allowEmptyShould(true); public static final ArchRule RULE_AFTER_EACH_NAMING_CONVENTION_MATCHED = methods() - .that().areAnnotatedWith(AfterEach.class).should().haveNameMatching("tearDown") + .that().areAnnotatedWith(AfterEach.class).should().haveNameMatching("^tearDown$") .allowEmptyShould(true); public static final ArchRule RULE_TEST_METHODS_ARE_PACKAGE_PRIVATE_CONVENTION_MATCHED = methods() - .that().areAnnotatedWith(Test.class).or().areAnnotatedWith(ParameterizedTest.class).should() + .that().areAnnotatedWith(Test.class) + .or().areAnnotatedWith(ParameterizedTest.class) + .or().areAnnotatedWith(RepeatedTest.class).or() + .areAnnotatedWith(TestTemplate.class).should() .notHaveModifier(JavaModifier.PROTECTED) .andShould().notHaveModifier(JavaModifier.PRIVATE) .andShould().notHaveModifier(JavaModifier.PUBLIC); public static final ArchRule RULE_TESTCLASSES_END_WITH_TEST_CONVENTION_MATCHED = methods() - .that().areAnnotatedWith(Test.class).or().areAnnotatedWith(ParameterizedTest.class) + .that().areAnnotatedWith(Test.class) + .or().areAnnotatedWith(ParameterizedTest.class) + .or().areAnnotatedWith(RepeatedTest.class).or() + .areAnnotatedWith(TestTemplate.class) .should(haveTopEnclosingClassEndingWithTest); }