package com.tngtech.archunit.junit; import java.lang.reflect.Method; import java.util.Collection; import com.tngtech.archunit.core.domain.JavaClass; import com.tngtech.archunit.core.domain.JavaClasses; import com.tngtech.archunit.junit.ArchUnitRunner.SharedCache; import com.tngtech.archunit.lang.ArchCondition; import com.tngtech.archunit.lang.ArchRule; import com.tngtech.archunit.lang.ConditionEvents; import org.assertj.core.api.iterable.Extractor; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.Description; import org.junit.runner.notification.RunNotifier; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import static com.google.common.base.Preconditions.checkState; import static com.tngtech.archunit.core.domain.TestUtils.invoke; import static com.tngtech.archunit.core.domain.TestUtils.javaClassesViaReflection; import static com.tngtech.archunit.junit.ArchUnitRunnerRunsRuleSetsTest.ArchTestWithRuleLibrary.someOtherMethodRuleName; import static com.tngtech.archunit.junit.ArchUnitRunnerRunsRuleSetsTest.Rules.someFieldRuleName; import static com.tngtech.archunit.junit.ArchUnitRunnerRunsRuleSetsTest.Rules.someMethodRuleName; import static com.tngtech.archunit.junit.ArchUnitRunnerTestUtils.getRule; import static com.tngtech.archunit.junit.ArchUnitRunnerTestUtils.newRunnerFor; import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.all; import static com.tngtech.archunit.lang.syntax.ClassesIdentityTransformer.classes; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class ArchUnitRunnerRunsRuleSetsTest { @Rule public final MockitoRule mockitoRule = MockitoJUnit.rule(); @Mock private SharedCache cache; @Mock private ClassCache classCache; @Mock private RunNotifier runNotifier; @Captor private ArgumentCaptor<Description> descriptionCaptor; @InjectMocks private ArchUnitRunner runnerForRuleSet = newRunnerFor(ArchTestWithRuleSet.class); @InjectMocks private ArchUnitRunner runnerForRuleLibrary = newRunnerFor(ArchTestWithRuleLibrary.class); private JavaClasses cachedClasses = javaClassesViaReflection(ArchUnitRunnerRunsRuleSetsTest.class); @Before public void setUp() { when(cache.get()).thenReturn(classCache); when(classCache.getClassesToAnalyzeFor(any(Class.class))).thenReturn(cachedClasses); } @Test public void should_find_children_in_rule_set() throws Exception { assertThat(runnerForRuleSet.getChildren()).as("Rules defined in Test Class").hasSize(2); assertThat(runnerForRuleSet.getChildren()) .extracting(resultOf("describeSelf")) .extractingResultOf("getMethodName") .as("Descriptions").containsOnly(someFieldRuleName, someMethodRuleName); } @Test public void should_find_children_in_rule_library() throws Exception { assertThat(runnerForRuleLibrary.getChildren()).as("Rules defined in Library").hasSize(3); assertThat(runnerForRuleLibrary.getChildren()) .extracting(resultOf("describeSelf")) .extractingResultOf("getMethodName") .as("Descriptions").containsOnly(someFieldRuleName, someMethodRuleName, someOtherMethodRuleName); } @Test public void can_run_rule_field() throws Exception { run(someFieldRuleName); } @Test public void can_run_rule_method() throws Exception { run(someMethodRuleName); } // extractingResultOf(..) only looks for public methods private Extractor<Object, Object> resultOf(final String methodName) { return new Extractor<Object, Object>() { @Override public Object extract(Object input) { Collection<Method> candidates = ReflectionUtils.getAllMethods(input.getClass(), new ReflectionUtils.Predicate<Method>() { @Override public boolean apply(Method input) { return input.getName().equals(methodName); } }); checkState(!candidates.isEmpty(), "Couldn't find any method named '%s' with hierarchy of %s", methodName, input.getClass().getName()); return invoke(candidates.iterator().next(), input); } }; } private void run(String ruleName) { ArchTestExecution rule = getRule(ruleName, runnerForRuleSet); runnerForRuleSet.runChild(rule, runNotifier); verify(runNotifier).fireTestStarted(any(Description.class)); verify(runNotifier).fireTestFinished(descriptionCaptor.capture()); assertThat(descriptionCaptor.getValue().toString()).contains(ruleName); } @AnalyzeClasses(packages = "some.pkg") public static class ArchTestWithRuleLibrary { public static final String someOtherMethodRuleName = "someOtherMethodRule"; @ArchTest public static final ArchRules rules = ArchRules.in(ArchTestWithRuleSet.class); @ArchTest public static void someOtherMethodRule(JavaClasses classes) { } } @AnalyzeClasses(packages = "some.pkg") public static class ArchTestWithRuleSet { @ArchTest public static final ArchRules rules = ArchRules.in(Rules.class); } public static class Rules { public static final String someFieldRuleName = "someFieldRule"; public static final String someMethodRuleName = "someMethodRule"; @ArchTest public static final ArchRule someFieldRule = all(classes()) .should(new ArchCondition<JavaClass>("satisfy something") { @Override public void check(JavaClass item, ConditionEvents events) { } }); @ArchTest public static void someMethodRule(JavaClasses classes) { } } }