Oliver
Oliver

Reputation: 4183

Making an ArchUnit test reusable

I have written my first ArchUnit test as normal unit test for one of my Maven modules. It should ensure, that there is a test class for each cleass in the production set of classes.

But I strugle to make it reuseable, so that I can use it in other (Maven) modules. In contrast to the examples in the documentation of ArchUnit, which uses @ArchTest, I have to deal with two set of classes.

Any idea?

@Test
void eachClassMustHaveACorrespondingTestClass() {
    String packageName = SystemSpec.class.getPackageName();
    String[] splitter = StringUtils.split(packageName, '.');
    String[] packages = ArrayUtils.subarray(splitter, 0, splitter.length - 1);
    String parentPackage = String.join(".", packages);

    JavaClasses productionClasses = new ClassFileImporter()
            .withImportOption(new ImportOption.DoNotIncludeTests())
            .importPackages(parentPackage)
            .that(new IsNotAnEnum())
            .that(new IsInterfaceWithDefaultMethods());

    Set<String> testClassNames = new ClassFileImporter()
            .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_JARS)
            .withImportOption(ImportOption.Predefined.ONLY_INCLUDE_TESTS)
            .importPackages(parentPackage) // Paket der Testklassen
            .stream()
            .map(JavaClass::getSimpleName)
            .collect(Collectors.toSet());

    ArchCondition<JavaClass> haveCorrespondingTestClass = new ArchCondition<>("have corresponding test class") {
        @Override
        public void check(JavaClass item, ConditionEvents events) {
            String testClassName = item.getSimpleName() + "Test";
            if (!testClassNames.contains(testClassName)) {
                String message = String.format("No test class found for %s", item.getFullName());
                events.add(SimpleConditionEvent.violated(item, message));
            }
        }
    };

    classes().should(haveCorrespondingTestClass).check(productionClasses);
}

Upvotes: 1

Views: 67

Answers (2)

Manfred
Manfred

Reputation: 3142

With ArchUnit's JUnit Support, you can also write tests using @ArchTest annotated methods (which, since ArchUnit#97, don't even have to be static anymore).

But maybe you can already use com.tngtech.archunit.library.GeneralCodingRules.testClassesShouldResideInTheSamePackageAsImplementation()?

Upvotes: 1

PeterMmm
PeterMmm

Reputation: 24630

Guessing SystemSpec.class is your class, and you want this more generic.

I solved this by creating an annotation. Then you can create a marker interface in your package and annotate with this custom annotation (or annotate any class).

Then with e.g. org.reflections.Reflection you can get this annotated interfaces, their package, the classes in the packages, etc and start your ArchUnit test on this set of classes.

Upvotes: 1

Related Questions