Reputation: 4183
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
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
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