Skip to content

Commit

Permalink
introduce ArchTests instead of ArchRules #538
Browse files Browse the repository at this point in the history
The term `ArchRules` is misleading, because it suggests that the class collects instances of `ArchRule`, while in fact it looks for members annotated with `@ArchTest`. This becomes particular clear, if you look at method declarations like `@ArchTest static void rule_method(JavaClasses classes) {..}`. I have thus introduced `ArchTests.in(someClass)` as a new version that makes this clearer (including some Javadoc this time) and kept the old `ArchRules` as a deprecated version for now to be backwards compatible.
I have duplicated quite some code (like whole test classes) and not unified much of the additional complexity by having `ArchTests` as well as `ArchRules`, since this is only temporary and we can kick it out in the near future.

Resolves: #525

Signed-off-by: Peter Gafert <peter.gafert@tngtech.com>
  • Loading branch information
codecholeric authored Feb 21, 2021
2 parents 5d0ea3d + dac33a3 commit 61a1c9e
Show file tree
Hide file tree
Showing 27 changed files with 615 additions and 118 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.tngtech.archunit.exampletest.junit4;

import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchRules;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.junit.ArchTests;
import com.tngtech.archunit.junit.ArchUnitRunner;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
Expand All @@ -12,11 +12,11 @@
@AnalyzeClasses(packages = "com.tngtech.archunit.example.layers")
public class RuleLibraryTest {
@ArchTest
public static final ArchRules LIBRARY = ArchRules.in(RuleSetsTest.class);
public static final ArchTests LIBRARY = ArchTests.in(RuleSetsTest.class);

@ArchTest
public static final ArchRules FURTHER_CODING_RULES = ArchRules.in(CodingRulesTest.class);
public static final ArchTests FURTHER_CODING_RULES = ArchTests.in(CodingRulesTest.class);

@ArchTest
public static final ArchRules SLICES_ISOLATION_RULES = ArchRules.in(SlicesIsolationTest.class);
public static final ArchTests SLICES_ISOLATION_RULES = ArchTests.in(SlicesIsolationTest.class);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.tngtech.archunit.exampletest.junit4;

import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchRules;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.junit.ArchTests;
import com.tngtech.archunit.junit.ArchUnitRunner;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
Expand All @@ -12,8 +12,8 @@
@AnalyzeClasses(packages = "com.tngtech.archunit.example.layers")
public class RuleSetsTest {
@ArchTest
private final ArchRules CODING_RULES = ArchRules.in(CodingRulesTest.class);
private final ArchTests CODING_RULES = ArchTests.in(CodingRulesTest.class);

@ArchTest
private final ArchRules NAMING_CONVENTION_RULES = ArchRules.in(NamingConventionTest.class);
private final ArchTests NAMING_CONVENTION_RULES = ArchTests.in(NamingConventionTest.class);
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package com.tngtech.archunit.exampletest.junit5;

import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchRules;
import com.tngtech.archunit.junit.ArchTag;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.junit.ArchTests;

@ArchTag("example")
@AnalyzeClasses(packages = "com.tngtech.archunit.example.layers")
class RuleLibraryTest {
@ArchTest
static final ArchRules LIBRARY = ArchRules.in(RuleSetsTest.class);
static final ArchTests LIBRARY = ArchTests.in(RuleSetsTest.class);

@ArchTest
static final ArchRules FURTHER_CODING_RULES = ArchRules.in(CodingRulesTest.class);
static final ArchTests FURTHER_CODING_RULES = ArchTests.in(CodingRulesTest.class);

@ArchTest
static final ArchRules SLICES_ISOLATION_RULES = ArchRules.in(SlicesIsolationTest.class);
static final ArchTests SLICES_ISOLATION_RULES = ArchTests.in(SlicesIsolationTest.class);
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package com.tngtech.archunit.exampletest.junit5;

import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchRules;
import com.tngtech.archunit.junit.ArchTag;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.junit.ArchTests;

@ArchTag("example")
@AnalyzeClasses(packages = "com.tngtech.archunit.example.layers")
class RuleSetsTest {
@ArchTest
private final ArchRules CODING_RULES = ArchRules.in(CodingRulesTest.class);
private final ArchTests CODING_RULES = ArchTests.in(CodingRulesTest.class);

@ArchTest
private final ArchRules NAMING_CONVENTION_RULES = ArchRules.in(NamingConventionTest.class);
private final ArchTests NAMING_CONVENTION_RULES = ArchTests.in(NamingConventionTest.class);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.core.importer.Location;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchRules;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.junit.ArchTests;
import com.tngtech.archunit.junit.ArchUnitRunner;
import com.tngtech.archunit.lang.ArchRule;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -57,7 +57,7 @@ public class ArchUnitArchitectureTest {
.whereLayer("Base").mayOnlyBeAccessedByLayers("Root", "Core", "Lang", "Library", "JUnit");

@ArchTest
public static final ArchRules importer_rules = ArchRules.in(ImporterRules.class);
public static final ArchTests importer_rules = ArchTests.in(ImporterRules.class);

@ArchTest
public static final ArchRule types_are_only_resolved_via_reflection_in_allowed_places =
Expand All @@ -66,7 +66,7 @@ public class ArchUnitArchitectureTest {
.as("no classes should illegally resolve classes via reflection");

@ArchTest
public static final ArchRules public_API_rules = ArchRules.in(PublicAPIRules.class);
public static final ArchTests public_API_rules = ArchTests.in(PublicAPIRules.class);

private static DescribedPredicate<JavaCall<?>> typeIsIllegallyResolvedViaReflection() {
DescribedPredicate<JavaCall<?>> explicitlyAllowedUsage =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ boolean shouldBeIgnored() {
}

static Set<ArchRuleDeclaration<?>> toDeclarations(
ArchRules rules, Class<?> testClass, Class<? extends Annotation> archTestAnnotationType, boolean forceIgnore) {
ArchTests archTests, Class<?> testClass, Class<? extends Annotation> archTestAnnotationType, boolean forceIgnore) {

ImmutableSet.Builder<ArchRuleDeclaration<?>> result = ImmutableSet.builder();
Class<?> definitionLocation = rules.getDefinitionLocation();
Class<?> definitionLocation = archTests.getDefinitionLocation();
for (Field field : getAllFields(definitionLocation, withAnnotation(archTestAnnotationType))) {
result.addAll(archRuleDeclarationsFrom(testClass, field, definitionLocation, archTestAnnotationType, forceIgnore));
}
Expand All @@ -84,13 +84,13 @@ static Set<ArchRuleDeclaration<?>> toDeclarations(
private static Set<ArchRuleDeclaration<?>> archRuleDeclarationsFrom(Class<?> testClass, Field field, Class<?> fieldOwner,
Class<? extends Annotation> archTestAnnotationType, boolean forceIgnore) {

return ArchRules.class.isAssignableFrom(field.getType()) ?
return ArchTests.class.isAssignableFrom(field.getType()) || ArchRules.class.isAssignableFrom(field.getType()) ?
toDeclarations(getArchRulesIn(field, fieldOwner), testClass, archTestAnnotationType, forceIgnore || elementShouldBeIgnored(field)) :
Collections.<ArchRuleDeclaration<?>>singleton(ArchRuleDeclaration.from(testClass, field, fieldOwner, forceIgnore));
}

private static ArchRules getArchRulesIn(Field field, Class<?> fieldOwner) {
ArchRules value = getValue(field, fieldOwner);
private static ArchTests getArchRulesIn(Field field, Class<?> fieldOwner) {
ArchTests value = ArchTests.from(getValue(field, fieldOwner));
return checkNotNull(value, "Field %s.%s is not initialized", fieldOwner.getName(), field.getName());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,22 +111,22 @@ private Collection<ArchTestExecution> findArchRuleFields() {

private Set<ArchTestExecution> findArchRulesIn(FrameworkField ruleField) {
boolean ignore = elementShouldBeIgnored(ruleField.getField());
if (ruleField.getType() == ArchRules.class) {
if (ruleField.getType() == ArchTests.class || ruleField.getType() == ArchRules.class) {
return asTestExecutions(getArchRules(ruleField.getField()), ignore);
}
return Collections.<ArchTestExecution>singleton(new ArchRuleExecution(getTestClass().getJavaClass(), ruleField.getField(), ignore));
}

private Set<ArchTestExecution> asTestExecutions(ArchRules archRules, boolean forceIgnore) {
private Set<ArchTestExecution> asTestExecutions(ArchTests archTests, boolean forceIgnore) {
ExecutionTransformer executionTransformer = new ExecutionTransformer();
for (ArchRuleDeclaration<?> declaration : toDeclarations(archRules, getTestClass().getJavaClass(), ArchTest.class, forceIgnore)) {
for (ArchRuleDeclaration<?> declaration : toDeclarations(archTests, getTestClass().getJavaClass(), ArchTest.class, forceIgnore)) {
declaration.handleWith(executionTransformer);
}
return executionTransformer.getExecutions();
}

private ArchRules getArchRules(Field field) {
return getValue(field, field.getDeclaringClass());
private ArchTests getArchRules(Field field) {
return ArchTests.from(getValue(field, field.getDeclaringClass()));
}

private Collection<ArchTestExecution> findArchRuleMethods() {
Expand Down
Loading

0 comments on commit 61a1c9e

Please sign in to comment.