Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Naming convention test of a class containing lambda with switch and enum #1019

Open
tomek-w-k opened this issue Dec 6, 2022 · 2 comments
Open

Comments

@tomek-w-k
Copy link

In a Spring Boot 2.7 project I implemented the following code:

package com.app.archunittest.constant;

public enum DummyEnum {
    FIRST,
    SECOND,
    THIRD
}
package com.app.archunittest.service;
import com.app.archunittest.constant.DummyEnum;
import org.springframework.stereotype.Service;
import java.util.Optional;

@Service
public class DummyService {

    private DummyEnum dummyEnum = DummyEnum.FIRST;

    public void dummyMethod() {
        Optional.ofNullable(dummyEnum)
                .ifPresent(de -> {
                    switch(de) {
                        case FIRST:
                            System.out.println("First item selected.");
                            break;
                        case SECOND:
                            System.out.println("Second item selected.");
                            break;
                        case THIRD:
                            System.out.println("Third item selected.");
                            break;
                    }
                });
    }
}

Then, with ArchUnit 1.0.1 I created a test for it:

import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;

@AnalyzeClasses(packages = "com.app.archunittest")
public class NamingConventionTest {

    @ArchTest
    static ArchRule serviceShouldBeSuffixed = classes()
            .that()
            .resideInAPackage("..service..")
            .should()
            .haveSimpleNameEndingWith("Service");
}

The test fails with an error:

java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] - Rule 'classes that reside in a package '..service..' should have simple name ending with 'Service'' was violated (1 times):
Class <com.app.archunittest.service.DummyService$1> does not have simple name ending with 'Service' in (DummyService.java:0)

Then I created a custom annotation @IgnoreArchUnitTest:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface IgnoreArchUnitTest {
}

and applied it to my service class. Modifiled the test:

@ArchTest
static ArchRule serviceShouldBeSuffixed = classes()
        .that()
        .resideInAPackage("..service..")
        .and()
        .areNotAnnotatedWith(IgnoreArchUnitTest.class)
        .should()
        .haveSimpleNameEndingWith("Service");

Service class should now be ignored by the test, but the error message I got was almost the same:

java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] - Rule 'classes that reside in a package '..service..' and are not annotated with @IgnoreArchUnitTest should have simple name ending with 'Service'' was violated (1 times):
Class <com.app.archunittest.service.DummyService$1> does not have simple name ending with 'Service' in (DummyService.java:0)

Ok, the error message rightly says that the Class <com.app.archunittest.service.DummyService$1> does not have simple name ending with 'Service'.
Thus, I removed the @IgnoreArchUnitTest annotation both from the service class and from the test. Added a new condition to the test for checking the "Service$1" suffix:

@ArchTest
static ArchRule serviceShouldBeSuffixed = classes()
        .that()
        .resideInAPackage("..service..")
        .should()
        .haveSimpleNameEndingWith("Service")
        .orShould()
        .haveSimpleNameEndingWith("Service$1");

Now, the error says:

java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] - Rule 'classes that reside in a package '..service..' should have simple name ending with 'Service' or should have simple name ending with 'Service$1'' was violated (1 times):
Class <com.app.archunittest.service.DummyService$1> does not have simple name ending with 'Service$1' in (DummyService.java:0) and Class <com.app.archunittest.service.DummyService$1> does not have simple name ending with 'Service' in (DummyService.java:0)

"Class <com.app.archunittest.service.DummyService$1> does not have simple name ending with 'Service$1'"
That's interesting...

However, when I modified my service method as below:

public void dummyMethod() {
    Optional.ofNullable(dummyEnum)
            .ifPresent(de -> {
                switch(de.name()) {
                    case "FIRST":
                        System.out.println("First item selected.");
                        break;
                    case "SECOND":
                        System.out.println("Second item selected.");
                        break;
                    case "THIRD":
                        System.out.println("Third item selected.");
                        break;
                }
            });
}

by replacing enum values with corresponding strings within the switch statement, the test passed successfully.

Is that a correct behavior of that test or maybe I did something wrong?

@hankem
Copy link
Member

hankem commented Dec 6, 2022

The synthetic class com.app.archunittest.service.DummyService$1 doesn't have a simple name (but "").
Technically, you could use orShould().haveNameMatching(".*\\.Service\\$1"), but you probably want to use the solution classes().that().doNotHaveModifier(JavaModifier.SYNTHETIC) from #1011 (comment).

@saugion
Copy link

saugion commented Mar 7, 2024

SYNTHETIC doesn't work for me, but i've noticed that these generated classes are recognised as anonymous. As a workaround i use .areNotAnonymousClasses() to exclude them from the evaluation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants