From e818a538544172dd1ade6124133fcab42ba3da95 Mon Sep 17 00:00:00 2001 From: Alex Soto Date: Mon, 9 Oct 2017 17:27:22 +0200 Subject: [PATCH 1/4] [WiP] Adds package annotation for affected tests --- api/pom.xml | 12 +++ .../testing/strategies/affected/Tests.java | 42 +++++++++ .../strategies/affected/TestsList.java | 14 +++ pom.xml | 7 ++ strategies/affected/pom.xml | 9 ++ .../affected/ClassDependenciesGraph.java | 90 +++++++++++++++++-- .../affected/ast/JavaAssistClass.java | 17 ++++ .../strategies/affected/ast/JavaClass.java | 5 ++ .../affected/ast/UnparsableClass.java | 11 +++ .../affected/ClassDependenciesGraphTest.java | 46 ++++++++++ .../fakeproject/main/superbiz/Alone.java | 4 + .../main/superbiz/component/Unwanted.java | 4 + .../affected/fakeproject/test/YTest.java | 19 ++++ .../affected/fakeproject/test/ZTest.java | 17 ++++ 14 files changed, 291 insertions(+), 6 deletions(-) create mode 100644 api/pom.xml create mode 100644 api/src/main/java/org/arquillian/smart/testing/strategies/affected/Tests.java create mode 100644 api/src/main/java/org/arquillian/smart/testing/strategies/affected/TestsList.java create mode 100644 strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/main/superbiz/Alone.java create mode 100644 strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/main/superbiz/component/Unwanted.java create mode 100644 strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/YTest.java create mode 100644 strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ZTest.java diff --git a/api/pom.xml b/api/pom.xml new file mode 100644 index 000000000..fb3edbc1d --- /dev/null +++ b/api/pom.xml @@ -0,0 +1,12 @@ + + + + smart-testing-parent + org.arquillian.smart.testing + 0.0.3-SNAPSHOT + + 4.0.0 + + api + + diff --git a/api/src/main/java/org/arquillian/smart/testing/strategies/affected/Tests.java b/api/src/main/java/org/arquillian/smart/testing/strategies/affected/Tests.java new file mode 100644 index 000000000..20e6d609c --- /dev/null +++ b/api/src/main/java/org/arquillian/smart/testing/strategies/affected/Tests.java @@ -0,0 +1,42 @@ +package org.arquillian.smart.testing.strategies.affected; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation used to set which production classes are tested in current test. + * By default it appends all classes defined in all attributes. + * + * If none of the attributes is set, then all production classes with same package as test and its subpackages are added. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Repeatable(TestsList.class) +@Documented +public @interface Tests { + + /** + * Packages of classes that needs to be added as tested classes in current test. You can set the package name "org.superbiz" which means only classes defined in this package, + * or ending with start (*) operator "org.superbiz.*" which means all classes of current package and its subpackages. + * @return Packages containing Java classes. + */ + String[] packages() default {}; + + /** + * Packages of classes that needs to be added as tested classes in current test. It is used Class to get the package. + * Notice that this is not + * @return Packages containing Java classes. + */ + Class[] packagesOf() default {}; + + /** + * Classes to be added as tested classes in current test. + * @return Classes + */ + Class[] classes() default {}; + +} diff --git a/api/src/main/java/org/arquillian/smart/testing/strategies/affected/TestsList.java b/api/src/main/java/org/arquillian/smart/testing/strategies/affected/TestsList.java new file mode 100644 index 000000000..f63c473a7 --- /dev/null +++ b/api/src/main/java/org/arquillian/smart/testing/strategies/affected/TestsList.java @@ -0,0 +1,14 @@ +package org.arquillian.smart.testing.strategies.affected; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Documented +public @interface TestsList { + Tests[] value(); +} diff --git a/pom.xml b/pom.xml index da4235984..340b5dae9 100644 --- a/pom.xml +++ b/pom.xml @@ -47,6 +47,7 @@ 3.8.0 1.16.1 3.21.0-GA + 2.7.4 1.0.1 3.0.0-beta-2 1.19 @@ -70,6 +71,7 @@ core + api surefire-provider junit-test-result-parser strategies/affected @@ -127,6 +129,11 @@ snakeyaml ${version.snakeyaml} + + io.github.lukehutch + fast-classpath-scanner + ${version.fast-classpath-scanner} + diff --git a/strategies/affected/pom.xml b/strategies/affected/pom.xml index c95ff1521..8fa8f180e 100644 --- a/strategies/affected/pom.xml +++ b/strategies/affected/pom.xml @@ -16,6 +16,11 @@ core ${project.version} + + org.arquillian.smart.testing + api + ${project.version} + org.arquillian.smart.testing strategy-changed @@ -29,6 +34,10 @@ org.jgrapht jgrapht-core + + io.github.lukehutch + fast-classpath-scanner + junit junit diff --git a/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraph.java b/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraph.java index 764bacfa3..bd195bcbe 100644 --- a/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraph.java +++ b/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraph.java @@ -27,13 +27,18 @@ */ package org.arquillian.smart.testing.strategies.affected; +import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner; import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.arquillian.smart.testing.api.TestVerifier; +import org.arquillian.smart.testing.logger.Log; +import org.arquillian.smart.testing.logger.Logger; import org.arquillian.smart.testing.strategies.affected.ast.JavaClass; import org.arquillian.smart.testing.strategies.affected.ast.JavaClassBuilder; import org.jgrapht.DirectedGraph; @@ -44,6 +49,7 @@ public class ClassDependenciesGraph { + private static final Logger logger = Log.getLogger(); private static final Filter coreJava = new Filter("", "java.*"); private final JavaClassBuilder builder; @@ -73,14 +79,86 @@ void buildTestDependencyGraph(Collection testJavaFiles) { // Then find dependencies for (String changedTestClassNames : testClassesNames) { - JavaClass javaClass = builder.getClassDescription(changedTestClassNames); - if (javaClass != null) { - addToIndex(new JavaElement(javaClass), javaClass.getImports()); + JavaClass testJavaClass = builder.getClassDescription(changedTestClassNames); + if (testJavaClass != null) { + final String[] imports = testJavaClass.getImports(); + final List manualProductionClasses = calculateManualAddedDependencies(testJavaClass); + manualProductionClasses.addAll(Arrays.asList(imports)); + addToIndex(new JavaElement(testJavaClass), manualProductionClasses); } } } - private void addToIndex(JavaElement javaElement, String[] imports) { + private List calculateManualAddedDependencies(JavaClass testJavaClass) { + final List manualDependencyClasses = new ArrayList<>(); + final Tests[] allTestsAnnotation = getAllAnnotations(testJavaClass); + + for (Tests tests : allTestsAnnotation) { + List packages = getPackages(testJavaClass.packageName(), tests); + for (String packag : packages) { + final String trimmedPackage = packag.trim(); + manualDependencyClasses.addAll(scanClassesFromPackage(trimmedPackage)); + } + } + + return manualDependencyClasses; + + } + + private Tests[] getAllAnnotations(JavaClass testJavaClass) { + + final Optional testsListOptional = testJavaClass.getAnnotationByType(TestsList.class); + + Tests[] tests = testsListOptional + .map(TestsList::value) + .orElseGet(() -> testJavaClass.getAnnotationByType(Tests.class) + .map(annotation -> new Tests[] {annotation}) + .orElse(new Tests[0])); + + + return tests; + } + + private List scanClassesFromPackage(String trimmedPackage) { + final List manualDependencyClasses = new ArrayList<>(); + if (trimmedPackage.endsWith(".*")) { + String realPackage = trimmedPackage.substring(0, trimmedPackage.indexOf(".*")); + final List classesOfPackage = + new FastClasspathScanner(realPackage).scan() + .getNamesOfAllClasses(); + + manualDependencyClasses.addAll( + classesOfPackage); + } else { + final List classesOfPackage = + new FastClasspathScanner(trimmedPackage).disableRecursiveScanning().scan() + .getNamesOfAllClasses(); + manualDependencyClasses.addAll( + classesOfPackage); + } + + if (manualDependencyClasses.isEmpty()) { + logger.warn("You set %s package as reference classes to run tests, but no classes found. Maybe a package refactor?", trimmedPackage); + } + + return manualDependencyClasses; + } + + private List getPackages(String testPackage, Tests tests) { + List packages = new ArrayList<>(); + if (tests.classes().length == 0 && tests.packages().length == 0 && tests.packagesOf().length == 0) { + packages.add(testPackage); + } else { + packages.addAll(Arrays.asList(tests.packages())); + + packages.addAll(Arrays.stream(tests.packagesOf()) + .map(clazz -> clazz.getPackage().getName()) + .collect(Collectors.toList())); + } + return packages; + } + + private void addToIndex(JavaElement javaElement, List imports) { addToGraph(javaElement); updateJavaElementWithImportReferences(javaElement, imports); } @@ -101,14 +179,14 @@ private void replaceVertex(JavaElement newClass) { } } - private void updateJavaElementWithImportReferences(JavaElement javaElementParentClass, String[] imports) { + private void updateJavaElementWithImportReferences(JavaElement javaElementParentClass, List imports) { for (String importz : imports) { if (addImport(javaElementParentClass, importz) && filter.shouldBeIncluded(importz) && this.enableTransitivity) { JavaClass javaClass = builder.getClassDescription(importz); if (javaClass != null) { - updateJavaElementWithImportReferences(javaElementParentClass, javaClass.getImports()); + updateJavaElementWithImportReferences(javaElementParentClass, Arrays.asList(javaClass.getImports())); } } } diff --git a/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ast/JavaAssistClass.java b/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ast/JavaAssistClass.java index 4fb8ff661..272ea1a6a 100644 --- a/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ast/JavaAssistClass.java +++ b/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ast/JavaAssistClass.java @@ -31,6 +31,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import javassist.CtClass; import javassist.CtField; @@ -53,10 +54,12 @@ public class JavaAssistClass extends AbstractJavaClass { private final String[] imports; private final String className; private File classFile; + private final CtClass classReference; JavaAssistClass(CtClass classReference) { imports = findImports(classReference); className = classReference.getName(); + this.classReference = classReference; } @Override @@ -163,6 +166,11 @@ public String getName() { return className; } + @Override + public String packageName() { + return classReference.getPackageName(); + } + @Override public String toString() { return getName(); @@ -176,4 +184,13 @@ public void setClassFile(File classFile) { public File getClassFile() { return classFile; } + + @Override + public Optional getAnnotationByType(Class type) { + try { + return Optional.ofNullable((T) this.classReference.getAnnotation(type)); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e); + } + } } diff --git a/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ast/JavaClass.java b/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ast/JavaClass.java index 22f459406..c8e417f28 100644 --- a/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ast/JavaClass.java +++ b/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ast/JavaClass.java @@ -28,10 +28,12 @@ package org.arquillian.smart.testing.strategies.affected.ast; import java.io.File; +import java.util.Optional; public interface JavaClass { String getName(); + String packageName(); /** * Gets the collection on classes that this class depends on. i.e. the list * of this classes children. @@ -39,4 +41,7 @@ public interface JavaClass { String[] getImports(); File getClassFile(); + + Optional getAnnotationByType(Class type); + } diff --git a/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ast/UnparsableClass.java b/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ast/UnparsableClass.java index 6b38a7d35..40dde4697 100644 --- a/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ast/UnparsableClass.java +++ b/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ast/UnparsableClass.java @@ -28,6 +28,7 @@ package org.arquillian.smart.testing.strategies.affected.ast; import java.io.File; +import java.util.Optional; public class UnparsableClass implements JavaClass { private static final String[] NO_IMPORT = new String[0]; @@ -43,6 +44,11 @@ public File getClassFile() { return null; } + @Override + public Optional getAnnotationByType(Class type) { + return Optional.empty(); + } + @Override public String[] getImports() { return NO_IMPORT; @@ -53,6 +59,11 @@ public String getName() { return classname; } + @Override + public String packageName() { + return ""; + } + @Override public String toString() { return "UnparsableClass{" + "classname='" + classname + '\'' + '}'; diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraphTest.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraphTest.java index d8202c094..c83299a28 100644 --- a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraphTest.java +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraphTest.java @@ -8,10 +8,14 @@ import org.arquillian.smart.testing.strategies.affected.fakeproject.main.D; import org.arquillian.smart.testing.strategies.affected.fakeproject.main.MyBusinessObject; import org.arquillian.smart.testing.strategies.affected.fakeproject.main.MyControllerObject; +import org.arquillian.smart.testing.strategies.affected.fakeproject.main.superbiz.Alone; +import org.arquillian.smart.testing.strategies.affected.fakeproject.main.superbiz.component.Unwanted; import org.arquillian.smart.testing.strategies.affected.fakeproject.test.ATest; import org.arquillian.smart.testing.strategies.affected.fakeproject.test.BTest; import org.arquillian.smart.testing.strategies.affected.fakeproject.test.CTest; import org.arquillian.smart.testing.strategies.affected.fakeproject.test.MyBusinessObjectTest; +import org.arquillian.smart.testing.strategies.affected.fakeproject.test.YTest; +import org.arquillian.smart.testing.strategies.affected.fakeproject.test.ZTest; import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.RestoreSystemProperties; @@ -140,6 +144,48 @@ public void should_detect_all_changes_transitive() { "org.arquillian.smart.testing.strategies.affected.fakeproject.test.ATest", "org.arquillian.smart.testing.strategies.affected.fakeproject.test.BTest"); } + @Test + public void should_detect_all_changes_adding_package_annotated_transitive() { + // given + final ClassDependenciesGraph + classDependenciesGraph = new ClassDependenciesGraph(new EndingWithTestTestVerifier()); + + final String testLocation = ZTest.class.getResource("ZTest.class").getPath(); + classDependenciesGraph.buildTestDependencyGraph(Arrays.asList(new File(testLocation))); + + // when + Set mainObjectsChanged = new HashSet<>(); + mainObjectsChanged.add(new File(Unwanted.class.getResource("Unwanted.class").getPath())); + + final Set testsDependingOn = classDependenciesGraph.findTestsDependingOn(mainObjectsChanged); + + // then + assertThat(testsDependingOn) + .containsExactlyInAnyOrder( + "org.arquillian.smart.testing.strategies.affected.fakeproject.test.ZTest"); + } + + @Test + public void should_detect_all_changes_adding_class_package_annotated_transitive() { + // given + final ClassDependenciesGraph + classDependenciesGraph = new ClassDependenciesGraph(new EndingWithTestTestVerifier()); + + final String testLocation = YTest.class.getResource("YTest.class").getPath(); + classDependenciesGraph.buildTestDependencyGraph(Arrays.asList(new File(testLocation))); + + // when + Set mainObjectsChanged = new HashSet<>(); + mainObjectsChanged.add(new File(Alone.class.getResource("Alone.class").getPath())); + + final Set testsDependingOn = classDependenciesGraph.findTestsDependingOn(mainObjectsChanged); + + // then + assertThat(testsDependingOn) + .containsExactlyInAnyOrder( + "org.arquillian.smart.testing.strategies.affected.fakeproject.test.YTest"); + } + @Test public void should_not_detect_all_changes_transitive_if_transitivity_is_disabled() { // given diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/main/superbiz/Alone.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/main/superbiz/Alone.java new file mode 100644 index 000000000..9e6e8f9fd --- /dev/null +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/main/superbiz/Alone.java @@ -0,0 +1,4 @@ +package org.arquillian.smart.testing.strategies.affected.fakeproject.main.superbiz; + +public class Alone { +} diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/main/superbiz/component/Unwanted.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/main/superbiz/component/Unwanted.java new file mode 100644 index 000000000..8e335da9c --- /dev/null +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/main/superbiz/component/Unwanted.java @@ -0,0 +1,4 @@ +package org.arquillian.smart.testing.strategies.affected.fakeproject.main.superbiz.component; + +public class Unwanted { +} diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/YTest.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/YTest.java new file mode 100644 index 000000000..6c8e08ee5 --- /dev/null +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/YTest.java @@ -0,0 +1,19 @@ +package org.arquillian.smart.testing.strategies.affected.fakeproject.test; + +import org.arquillian.smart.testing.strategies.affected.Tests; +import org.arquillian.smart.testing.strategies.affected.fakeproject.main.superbiz.Alone; +import org.junit.Ignore; +import org.junit.Test; + +// Test ignored because it is a test that is used to in tests and not to be run as real test by test runner +@Ignore +@Tests(packagesOf = Alone.class) +public class YTest { + + + @Test + public void black_box() { + System.out.println("Black Box Testing"); + } + +} diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ZTest.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ZTest.java new file mode 100644 index 000000000..1e0528028 --- /dev/null +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ZTest.java @@ -0,0 +1,17 @@ +package org.arquillian.smart.testing.strategies.affected.fakeproject.test; + +import org.arquillian.smart.testing.strategies.affected.Tests; +import org.junit.Ignore; +import org.junit.Test; + +// Test ignored because it is a test that is used to in tests and not to be run as real test by test runner +@Ignore +@Tests(packages = "org.arquillian.smart.testing.strategies.affected.fakeproject.main.superbiz.*") +public class ZTest { + + @Test + public void black_box() { + System.out.println("Black Box Testing"); + } + +} From 02554bb7347e1a835b2208162f6efd84f90ca2d9 Mon Sep 17 00:00:00 2001 From: Alex Soto Date: Tue, 31 Oct 2017 11:10:32 +0100 Subject: [PATCH 2/4] Updates pom.xml --- api/pom.xml | 2 +- .../testing/strategies/affected/fakeproject/test/YTest.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index fb3edbc1d..7503452d5 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -3,7 +3,7 @@ smart-testing-parent org.arquillian.smart.testing - 0.0.3-SNAPSHOT + 0.0.4-SNAPSHOT 4.0.0 diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/YTest.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/YTest.java index 6c8e08ee5..b7ad1f2c3 100644 --- a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/YTest.java +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/YTest.java @@ -5,12 +5,11 @@ import org.junit.Ignore; import org.junit.Test; -// Test ignored because it is a test that is used to in tests and not to be run as real test by test runner +// Test ignored because it is used internally @Ignore @Tests(packagesOf = Alone.class) public class YTest { - @Test public void black_box() { System.out.println("Black Box Testing"); From 971cf8d6f46283e3d5e5bf6ee40276038336f0eb Mon Sep 17 00:00:00 2001 From: Alex Soto Date: Tue, 31 Oct 2017 15:13:11 +0100 Subject: [PATCH 3/4] Minor changes and updates documentation --- .../testing/strategies/affected/Tests.java | 4 +-- docs/configuration.adoc | 30 +++++++++++++++++++ .../affected/ClassDependenciesGraph.java | 2 +- .../affected/fakeproject/test/ZTest.java | 5 ++-- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/org/arquillian/smart/testing/strategies/affected/Tests.java b/api/src/main/java/org/arquillian/smart/testing/strategies/affected/Tests.java index 20e6d609c..616d5cd93 100644 --- a/api/src/main/java/org/arquillian/smart/testing/strategies/affected/Tests.java +++ b/api/src/main/java/org/arquillian/smart/testing/strategies/affected/Tests.java @@ -11,7 +11,7 @@ * Annotation used to set which production classes are tested in current test. * By default it appends all classes defined in all attributes. * - * If none of the attributes is set, then all production classes with same package as test and its subpackages are added. + * If none of the attributes are set, then all production classes with same package as test and its subpackages are added. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @@ -28,7 +28,7 @@ /** * Packages of classes that needs to be added as tested classes in current test. It is used Class to get the package. - * Notice that this is not + * Notice that in this case subpackages are not scanned. * @return Packages containing Java classes. */ Class[] packagesOf() default {}; diff --git a/docs/configuration.adoc b/docs/configuration.adoc index 5d9185a6f..fc91274ec 100644 --- a/docs/configuration.adoc +++ b/docs/configuration.adoc @@ -138,6 +138,36 @@ IMPORTANT: This strategy is currently only applicable for _white box_ testing ap WARNING: At this moment, this strategy does not work with Java 9. +===== Explicitly Set + +By default affected strategy uses _imports_ of tests to build the graph of dependencies. +This approach is fine for unit tests (white box tests) but might not work in all cases of high level tests (black box test). + +There are some test technologies that allows you to deploy an application locally and then run tests against it. +For example Wildfly Swarm has `@DefaultDeployment` annotation or for example Spring (Boot) deploys all application automatically. + +This means that production classes are not directly imported into the test, so there is no way to get a relationship between test and production classes. +For this reason `affected` provides an annotation to set package(s) of production classes that are deployed by the test. + +The first thing you need to do is register next artifact into your build script: `org.arquillian.smart.testing:api:`. + +Then you can annotate your test with `org.arquillian.smart.testing.strategies.affected.Tests` annotation. + +For example: + +[source, java] +---- +include::../strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ZTest.java[tag=docs] +---- + +In previous example all classes belonging to packages and subpackages specified at `packages` attribute are considered as classes used by the test. + +You can also use `packageOf` attribute to set a reference class. +With this attribute all classes that are placed in the same package as the reference class are considered as classes used by the test. +With this approach your tests are resilient to package name changes. + +If none of the attributes are set, then all production classes with same package as test and its subpackages are added automatically as classes used by the test. + ==== Failed `Failed` strategy just gets all tests that failed from previous executions and mark them as *important* tests to run first (_ordering_) or not filtered (_selecting_). diff --git a/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraph.java b/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraph.java index bd195bcbe..bb8806ee1 100644 --- a/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraph.java +++ b/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraph.java @@ -147,7 +147,7 @@ private List scanClassesFromPackage(String trimmedPackage) { private List getPackages(String testPackage, Tests tests) { List packages = new ArrayList<>(); if (tests.classes().length == 0 && tests.packages().length == 0 && tests.packagesOf().length == 0) { - packages.add(testPackage); + packages.add(testPackage + ".*"); } else { packages.addAll(Arrays.asList(tests.packages())); diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ZTest.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ZTest.java index 1e0528028..42633681f 100644 --- a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ZTest.java +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ZTest.java @@ -4,11 +4,12 @@ import org.junit.Ignore; import org.junit.Test; -// Test ignored because it is a test that is used to in tests and not to be run as real test by test runner +// Test ignored because it is used internally @Ignore +//tag::docs[] @Tests(packages = "org.arquillian.smart.testing.strategies.affected.fakeproject.main.superbiz.*") public class ZTest { - +//end::docs[] @Test public void black_box() { System.out.println("Black Box Testing"); From 34859ea47e0ec9f25e0b57385851853ac9a32766 Mon Sep 17 00:00:00 2001 From: Alex Soto Date: Thu, 2 Nov 2017 18:04:05 +0100 Subject: [PATCH 4/4] Code review changes and creation of ftest --- .../{Tests.java => ComponentUnderTest.java} | 4 +- ...estsList.java => ComponentsUnderTest.java} | 4 +- docs/configuration.adoc | 8 +-- ...TestsSelectionExecutionFunctionalTest.java | 50 +++++++++++++ .../affected/ClassDependenciesGraph.java | 24 +++---- .../affected/ClassDependenciesGraphTest.java | 70 ++++++++++--------- .../affected/fakeproject/test/ATest.java | 3 +- .../affected/fakeproject/test/BTest.java | 3 +- .../affected/fakeproject/test/CTest.java | 3 +- .../test/MyBusinessObjectTest.java | 3 +- .../test/MyBusinessObjectTestCase.java | 3 +- .../test/MySecondBusinessObjectTest.java | 3 +- .../affected/fakeproject/test/YTest.java | 7 +- .../affected/fakeproject/test/ZTest.java | 7 +- 14 files changed, 120 insertions(+), 72 deletions(-) rename api/src/main/java/org/arquillian/smart/testing/strategies/affected/{Tests.java => ComponentUnderTest.java} (94%) rename api/src/main/java/org/arquillian/smart/testing/strategies/affected/{TestsList.java => ComponentsUnderTest.java} (81%) create mode 100644 functional-tests/test-bed/src/test/java/org/arquillian/smart/testing/ftest/affected/LocalChangesAffectedAnnotationTestsSelectionExecutionFunctionalTest.java diff --git a/api/src/main/java/org/arquillian/smart/testing/strategies/affected/Tests.java b/api/src/main/java/org/arquillian/smart/testing/strategies/affected/ComponentUnderTest.java similarity index 94% rename from api/src/main/java/org/arquillian/smart/testing/strategies/affected/Tests.java rename to api/src/main/java/org/arquillian/smart/testing/strategies/affected/ComponentUnderTest.java index 616d5cd93..a139f3ef7 100644 --- a/api/src/main/java/org/arquillian/smart/testing/strategies/affected/Tests.java +++ b/api/src/main/java/org/arquillian/smart/testing/strategies/affected/ComponentUnderTest.java @@ -15,9 +15,9 @@ */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) -@Repeatable(TestsList.class) +@Repeatable(ComponentsUnderTest.class) @Documented -public @interface Tests { +public @interface ComponentUnderTest { /** * Packages of classes that needs to be added as tested classes in current test. You can set the package name "org.superbiz" which means only classes defined in this package, diff --git a/api/src/main/java/org/arquillian/smart/testing/strategies/affected/TestsList.java b/api/src/main/java/org/arquillian/smart/testing/strategies/affected/ComponentsUnderTest.java similarity index 81% rename from api/src/main/java/org/arquillian/smart/testing/strategies/affected/TestsList.java rename to api/src/main/java/org/arquillian/smart/testing/strategies/affected/ComponentsUnderTest.java index f63c473a7..7ca39b471 100644 --- a/api/src/main/java/org/arquillian/smart/testing/strategies/affected/TestsList.java +++ b/api/src/main/java/org/arquillian/smart/testing/strategies/affected/ComponentsUnderTest.java @@ -9,6 +9,6 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented -public @interface TestsList { - Tests[] value(); +public @interface ComponentsUnderTest { + ComponentUnderTest[] value(); } diff --git a/docs/configuration.adoc b/docs/configuration.adoc index fc91274ec..b95563e4f 100644 --- a/docs/configuration.adoc +++ b/docs/configuration.adoc @@ -140,18 +140,18 @@ WARNING: At this moment, this strategy does not work with Java 9. ===== Explicitly Set -By default affected strategy uses _imports_ of tests to build the graph of dependencies. +By default affected strategy uses _imports_ of tests to build the graph of collaborators. This approach is fine for unit tests (white box tests) but might not work in all cases of high level tests (black box test). There are some test technologies that allows you to deploy an application locally and then run tests against it. -For example Wildfly Swarm has `@DefaultDeployment` annotation or for example Spring (Boot) deploys all application automatically. +For example Wildfly Swarm has `@DefaultDeployment` annotation or Spring (Boot) deploys all application automatically. This means that production classes are not directly imported into the test, so there is no way to get a relationship between test and production classes. For this reason `affected` provides an annotation to set package(s) of production classes that are deployed by the test. -The first thing you need to do is register next artifact into your build script: `org.arquillian.smart.testing:api:`. +The first thing you need to do is register following artifact into your build script: `org.arquillian.smart.testing:api:`. -Then you can annotate your test with `org.arquillian.smart.testing.strategies.affected.Tests` annotation. +Then you can annotate your test with `org.arquillian.smart.testing.strategies.affected.ComponentUnderTest` annotation. For example: diff --git a/functional-tests/test-bed/src/test/java/org/arquillian/smart/testing/ftest/affected/LocalChangesAffectedAnnotationTestsSelectionExecutionFunctionalTest.java b/functional-tests/test-bed/src/test/java/org/arquillian/smart/testing/ftest/affected/LocalChangesAffectedAnnotationTestsSelectionExecutionFunctionalTest.java new file mode 100644 index 000000000..d336a4b26 --- /dev/null +++ b/functional-tests/test-bed/src/test/java/org/arquillian/smart/testing/ftest/affected/LocalChangesAffectedAnnotationTestsSelectionExecutionFunctionalTest.java @@ -0,0 +1,50 @@ +package org.arquillian.smart.testing.ftest.affected; + +import java.util.Collection; +import org.arquillian.smart.testing.ftest.testbed.project.Project; +import org.arquillian.smart.testing.ftest.testbed.project.TestResults; +import org.arquillian.smart.testing.ftest.testbed.testresults.TestResult; +import org.arquillian.smart.testing.mvn.ext.dependencies.ExtensionVersion; +import org.arquillian.smart.testing.rules.TestBed; +import org.arquillian.smart.testing.rules.git.GitClone; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; + +import static org.arquillian.smart.testing.ftest.testbed.TestRepository.testRepository; +import static org.arquillian.smart.testing.ftest.testbed.configuration.Mode.SELECTING; +import static org.arquillian.smart.testing.ftest.testbed.configuration.Strategy.AFFECTED; +import static org.assertj.core.api.Assertions.assertThat; + +public class LocalChangesAffectedAnnotationTestsSelectionExecutionFunctionalTest { + + @ClassRule + public static final GitClone GIT_CLONE = new GitClone(testRepository()); + + @Rule + public final TestBed testBed = new TestBed(GIT_CLONE); + + @Test + public void should_only_execute_tests_with_affected_changes_annotated() throws Exception { + // given + final Project project = testBed.getProject(); + + project.configureSmartTesting() + .executionOrder(AFFECTED) + .inMode(SELECTING) + .enable(); + + final Collection expectedTestResults = project + .applyAsLocalChanges("Uses annotation to detect affected classes"); + + // when + final TestResults actualTestResults = project.build("config/impl-base") + .options().withSystemProperties("smart.testing.version", ExtensionVersion.version().toString()) + .configure() + .run(); + + // then + assertThat(actualTestResults.accumulatedPerTestClass()).containsAll(expectedTestResults).hasSameSizeAs(expectedTestResults); + } + +} diff --git a/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraph.java b/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraph.java index bb8806ee1..55be9a2c7 100644 --- a/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraph.java +++ b/strategies/affected/src/main/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraph.java @@ -91,12 +91,12 @@ void buildTestDependencyGraph(Collection testJavaFiles) { private List calculateManualAddedDependencies(JavaClass testJavaClass) { final List manualDependencyClasses = new ArrayList<>(); - final Tests[] allTestsAnnotation = getAllAnnotations(testJavaClass); + final ComponentUnderTest[] allTestsAnnotation = getAllAnnotations(testJavaClass); - for (Tests tests : allTestsAnnotation) { + for (ComponentUnderTest tests : allTestsAnnotation) { List packages = getPackages(testJavaClass.packageName(), tests); - for (String packag : packages) { - final String trimmedPackage = packag.trim(); + for (String pkg : packages) { + final String trimmedPackage = pkg.trim(); manualDependencyClasses.addAll(scanClassesFromPackage(trimmedPackage)); } } @@ -105,15 +105,15 @@ private List calculateManualAddedDependencies(JavaClass testJavaClass) { } - private Tests[] getAllAnnotations(JavaClass testJavaClass) { + private ComponentUnderTest[] getAllAnnotations(JavaClass testJavaClass) { - final Optional testsListOptional = testJavaClass.getAnnotationByType(TestsList.class); + final Optional testsListOptional = testJavaClass.getAnnotationByType(ComponentsUnderTest.class); - Tests[] tests = testsListOptional - .map(TestsList::value) - .orElseGet(() -> testJavaClass.getAnnotationByType(Tests.class) - .map(annotation -> new Tests[] {annotation}) - .orElse(new Tests[0])); + ComponentUnderTest[] tests = testsListOptional + .map(ComponentsUnderTest::value) + .orElseGet(() -> testJavaClass.getAnnotationByType(ComponentUnderTest.class) + .map(annotation -> new ComponentUnderTest[] {annotation}) + .orElse(new ComponentUnderTest[0])); return tests; @@ -144,7 +144,7 @@ private List scanClassesFromPackage(String trimmedPackage) { return manualDependencyClasses; } - private List getPackages(String testPackage, Tests tests) { + private List getPackages(String testPackage, ComponentUnderTest tests) { List packages = new ArrayList<>(); if (tests.classes().length == 0 && tests.packages().length == 0 && tests.packagesOf().length == 0) { packages.add(testPackage + ".*"); diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraphTest.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraphTest.java index c83299a28..f058eb5cf 100644 --- a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraphTest.java +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/ClassDependenciesGraphTest.java @@ -5,6 +5,7 @@ import java.util.HashSet; import java.util.Set; import net.jcip.annotations.NotThreadSafe; +import org.arquillian.smart.testing.strategies.affected.fakeproject.main.A; import org.arquillian.smart.testing.strategies.affected.fakeproject.main.D; import org.arquillian.smart.testing.strategies.affected.fakeproject.main.MyBusinessObject; import org.arquillian.smart.testing.strategies.affected.fakeproject.main.MyControllerObject; @@ -14,6 +15,7 @@ import org.arquillian.smart.testing.strategies.affected.fakeproject.test.BTest; import org.arquillian.smart.testing.strategies.affected.fakeproject.test.CTest; import org.arquillian.smart.testing.strategies.affected.fakeproject.test.MyBusinessObjectTest; +import org.arquillian.smart.testing.strategies.affected.fakeproject.test.MySecondBusinessObjectTest; import org.arquillian.smart.testing.strategies.affected.fakeproject.test.YTest; import org.arquillian.smart.testing.strategies.affected.fakeproject.test.ZTest; import org.junit.Rule; @@ -36,12 +38,12 @@ public void should_detect_simple_test_to_execute() { final ClassDependenciesGraph classDependenciesGraph = new ClassDependenciesGraph(new EndingWithTestTestVerifier()); - final String testLocation = MyBusinessObjectTest.class.getResource("MyBusinessObjectTest.class").getPath(); + final String testLocation = getClassLocation(MyBusinessObjectTest.class); classDependenciesGraph.buildTestDependencyGraph(singletonList(new File(testLocation))); // when Set mainObjectsChanged = new HashSet<>(); - mainObjectsChanged.add(new File(MyBusinessObject.class.getResource("MyBusinessObject.class").getPath())); + mainObjectsChanged.add(new File(getClassLocation(MyBusinessObject.class))); final Set testsDependingOn = classDependenciesGraph.findTestsDependingOn(mainObjectsChanged); @@ -56,13 +58,13 @@ public void should_detect_multiple_tests_to_execute_against_same_main_class() { final ClassDependenciesGraph classDependenciesGraph = new ClassDependenciesGraph(new EndingWithTestTestVerifier()); - final String testLocation = MyBusinessObjectTest.class.getResource("MyBusinessObjectTest.class").getPath(); - final String testLocation2 = MyBusinessObjectTest.class.getResource("MySecondBusinessObjectTest.class").getPath(); + final String testLocation = getClassLocation(MyBusinessObjectTest.class); + final String testLocation2 = getClassLocation(MySecondBusinessObjectTest.class); classDependenciesGraph.buildTestDependencyGraph(Arrays.asList(new File(testLocation), new File(testLocation2))); // when Set mainObjectsChanged = new HashSet<>(); - mainObjectsChanged.add(new File(MyBusinessObject.class.getResource("MyBusinessObject.class").getPath())); + mainObjectsChanged.add(new File(getClassLocation(MyBusinessObject.class))); final Set testsDependingOn = classDependenciesGraph.findTestsDependingOn(mainObjectsChanged); @@ -79,13 +81,13 @@ public void should_detect_test_with_multiple_main_classes() { final ClassDependenciesGraph classDependenciesGraph = new ClassDependenciesGraph(new EndingWithTestTestVerifier()); - final String testLocation = MyBusinessObjectTest.class.getResource("MyBusinessObjectTest.class").getPath(); - final String testLocation2 = MyBusinessObjectTest.class.getResource("MySecondBusinessObjectTest.class").getPath(); + final String testLocation = getClassLocation(MyBusinessObjectTest.class); + final String testLocation2 = getClassLocation(MySecondBusinessObjectTest.class); classDependenciesGraph.buildTestDependencyGraph(Arrays.asList(new File(testLocation), new File(testLocation2))); // when Set mainObjectsChanged = new HashSet<>(); - mainObjectsChanged.add(new File(MyControllerObject.class.getResource("MyControllerObject.class").getPath())); + mainObjectsChanged.add(new File(getClassLocation(MyControllerObject.class))); final Set testsDependingOn = classDependenciesGraph.findTestsDependingOn(mainObjectsChanged); @@ -101,14 +103,14 @@ public void should_detect_multiple_tests_to_execute_against_same_main_class_avoi final ClassDependenciesGraph classDependenciesGraph = new ClassDependenciesGraph(new EndingWithTestTestVerifier()); - final String testLocation = MyBusinessObjectTest.class.getResource("MyBusinessObjectTest.class").getPath(); - final String testLocation2 = MyBusinessObjectTest.class.getResource("MySecondBusinessObjectTest.class").getPath(); + final String testLocation = getClassLocation(MyBusinessObjectTest.class); + final String testLocation2 = getClassLocation(MySecondBusinessObjectTest.class); classDependenciesGraph.buildTestDependencyGraph(Arrays.asList(new File(testLocation), new File(testLocation2))); // when Set mainObjectsChanged = new HashSet<>(); - mainObjectsChanged.add(new File(MyBusinessObject.class.getResource("MyBusinessObject.class").getPath())); - mainObjectsChanged.add(new File(MyControllerObject.class.getResource("MyControllerObject.class").getPath())); + mainObjectsChanged.add(new File(getClassLocation(MyBusinessObject.class))); + mainObjectsChanged.add(new File(getClassLocation(MyControllerObject.class))); final Set testsDependingOn = classDependenciesGraph.findTestsDependingOn(mainObjectsChanged); @@ -126,15 +128,15 @@ public void should_detect_all_changes_transitive() { final ClassDependenciesGraph classDependenciesGraph = new ClassDependenciesGraph(new EndingWithTestTestVerifier()); - final String testLocation = ATest.class.getResource("ATest.class").getPath(); - final String testLocation2 = BTest.class.getResource("BTest.class").getPath(); - final String testLocation3 = CTest.class.getResource("CTest.class").getPath(); + final String testLocation = getClassLocation(ATest.class); + final String testLocation2 = getClassLocation(BTest.class); + final String testLocation3 = getClassLocation(CTest.class); classDependenciesGraph.buildTestDependencyGraph(Arrays.asList(new File(testLocation), new File(testLocation2), new File(testLocation3))); // when Set mainObjectsChanged = new HashSet<>(); - mainObjectsChanged.add(new File(D.class.getResource("D.class").getPath())); + mainObjectsChanged.add(new File(getClassLocation(D.class))); final Set testsDependingOn = classDependenciesGraph.findTestsDependingOn(mainObjectsChanged); @@ -150,12 +152,12 @@ public void should_detect_all_changes_adding_package_annotated_transitive() { final ClassDependenciesGraph classDependenciesGraph = new ClassDependenciesGraph(new EndingWithTestTestVerifier()); - final String testLocation = ZTest.class.getResource("ZTest.class").getPath(); + final String testLocation = getClassLocation(ZTest.class); classDependenciesGraph.buildTestDependencyGraph(Arrays.asList(new File(testLocation))); // when Set mainObjectsChanged = new HashSet<>(); - mainObjectsChanged.add(new File(Unwanted.class.getResource("Unwanted.class").getPath())); + mainObjectsChanged.add(new File(getClassLocation(Unwanted.class))); final Set testsDependingOn = classDependenciesGraph.findTestsDependingOn(mainObjectsChanged); @@ -171,12 +173,12 @@ public void should_detect_all_changes_adding_class_package_annotated_transitive( final ClassDependenciesGraph classDependenciesGraph = new ClassDependenciesGraph(new EndingWithTestTestVerifier()); - final String testLocation = YTest.class.getResource("YTest.class").getPath(); + final String testLocation = getClassLocation(YTest.class); classDependenciesGraph.buildTestDependencyGraph(Arrays.asList(new File(testLocation))); // when Set mainObjectsChanged = new HashSet<>(); - mainObjectsChanged.add(new File(Alone.class.getResource("Alone.class").getPath())); + mainObjectsChanged.add(new File(getClassLocation(Alone.class))); final Set testsDependingOn = classDependenciesGraph.findTestsDependingOn(mainObjectsChanged); @@ -193,15 +195,15 @@ public void should_not_detect_all_changes_transitive_if_transitivity_is_disabled final ClassDependenciesGraph classDependenciesGraph = new ClassDependenciesGraph(new EndingWithTestTestVerifier()); - final String testLocation = ATest.class.getResource("ATest.class").getPath(); - final String testLocation2 = BTest.class.getResource("BTest.class").getPath(); - final String testLocation3 = CTest.class.getResource("CTest.class").getPath(); + final String testLocation = getClassLocation(ATest.class); + final String testLocation2 = getClassLocation(BTest.class); + final String testLocation3 = getClassLocation(CTest.class); classDependenciesGraph.buildTestDependencyGraph(Arrays.asList(new File(testLocation), new File(testLocation2), new File(testLocation3))); // when Set mainObjectsChanged = new HashSet<>(); - mainObjectsChanged.add(new File(D.class.getResource("D.class").getPath())); + mainObjectsChanged.add(new File(getClassLocation(D.class))); final Set testsDependingOn = classDependenciesGraph.findTestsDependingOn(mainObjectsChanged); @@ -217,15 +219,15 @@ public void should_exclude_imports_if_property_set() { final ClassDependenciesGraph classDependenciesGraph = new ClassDependenciesGraph(new EndingWithTestTestVerifier()); - final String testLocation = ATest.class.getResource("ATest.class").getPath(); - final String testLocation2 = BTest.class.getResource("BTest.class").getPath(); - final String testLocation3 = CTest.class.getResource("CTest.class").getPath(); + final String testLocation = getClassLocation(ATest.class); + final String testLocation2 = getClassLocation(BTest.class); + final String testLocation3 = getClassLocation(CTest.class); classDependenciesGraph.buildTestDependencyGraph(Arrays.asList(new File(testLocation), new File(testLocation2), new File(testLocation3))); // when Set mainObjectsChanged = new HashSet<>(); - mainObjectsChanged.add(new File(D.class.getResource("D.class").getPath())); + mainObjectsChanged.add(new File(getClassLocation(D.class))); final Set testsDependingOn = classDependenciesGraph.findTestsDependingOn(mainObjectsChanged); @@ -241,16 +243,16 @@ public void should_include_only_imports_if_property_set() { final ClassDependenciesGraph classDependenciesGraph = new ClassDependenciesGraph(new EndingWithTestTestVerifier()); - final String testLocation = ATest.class.getResource("ATest.class").getPath(); - final String testLocation2 = BTest.class.getResource("BTest.class").getPath(); - final String testLocation3 = CTest.class.getResource("CTest.class").getPath(); + final String testLocation = getClassLocation(ATest.class); + final String testLocation2 = getClassLocation(BTest.class); + final String testLocation3 = getClassLocation(CTest.class); classDependenciesGraph.buildTestDependencyGraph(Arrays.asList(new File(testLocation), new File(testLocation2), new File(testLocation3))); // when Set mainObjectsChanged = new HashSet<>(); - mainObjectsChanged.add(new File(D.class.getResource("A.class").getPath())); + mainObjectsChanged.add(new File(getClassLocation(A.class))); final Set testsDependingOn = classDependenciesGraph.findTestsDependingOn(mainObjectsChanged); @@ -261,4 +263,8 @@ public void should_include_only_imports_if_property_set() { "org.arquillian.smart.testing.strategies.affected.fakeproject.test.ATest"); } + private String getClassLocation(Class clazz) { + return clazz.getResource(clazz.getSimpleName() + ".class").getPath(); + } + } diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ATest.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ATest.java index 2dfa26400..8e956dc07 100644 --- a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ATest.java +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ATest.java @@ -4,8 +4,7 @@ import org.junit.Ignore; import org.junit.Test; -// Test ignored because it is a test that is used to in tests and not to be run as real test by test runner -@Ignore +@Ignore("Test ignored because it is used internally") public class ATest { private A a; diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/BTest.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/BTest.java index ef4f6d93b..d58798c8e 100644 --- a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/BTest.java +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/BTest.java @@ -4,8 +4,7 @@ import org.junit.Ignore; import org.junit.Test; -// Test ignored because it is a test that is used to in tests and not to be run as real test by test runner -@Ignore +@Ignore("Test ignored because it is used internally") public class BTest { private B b; diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/CTest.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/CTest.java index fca32a88c..abbc225fb 100644 --- a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/CTest.java +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/CTest.java @@ -4,8 +4,7 @@ import org.junit.Ignore; import org.junit.Test; -// Test ignored because it is a test that is used to in tests and not to be run as real test by test runner -@Ignore +@Ignore("Test ignored because it is used internally") public class CTest { private C c; diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/MyBusinessObjectTest.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/MyBusinessObjectTest.java index de86d2b48..e83bef77f 100644 --- a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/MyBusinessObjectTest.java +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/MyBusinessObjectTest.java @@ -4,8 +4,7 @@ import org.junit.Ignore; import org.junit.Test; -// Test ignored because it is a test that is used to in tests and not to be run as real test by test runner -@Ignore +@Ignore("Test ignored because it is used internally") public class MyBusinessObjectTest { private MyBusinessObject myBusinessObject; diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/MyBusinessObjectTestCase.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/MyBusinessObjectTestCase.java index d7e4ba97e..24c3ade2c 100644 --- a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/MyBusinessObjectTestCase.java +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/MyBusinessObjectTestCase.java @@ -4,8 +4,7 @@ import org.junit.Ignore; import org.junit.Test; -// Test ignored because it is a test that is used to in tests and not to be run as real test by test runner -@Ignore +@Ignore("Test ignored because it is used internally") public class MyBusinessObjectTestCase { private MyBusinessObject myBusinessObject; diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/MySecondBusinessObjectTest.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/MySecondBusinessObjectTest.java index 087059f89..893c31e58 100644 --- a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/MySecondBusinessObjectTest.java +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/MySecondBusinessObjectTest.java @@ -5,8 +5,7 @@ import org.junit.Ignore; import org.junit.Test; -// Test ignored because it is a test that is used to in tests and not to be run as real test by test runner -@Ignore +@Ignore("Test ignored because it is used internally") public class MySecondBusinessObjectTest { private MyBusinessObject myBusinessObject; diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/YTest.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/YTest.java index b7ad1f2c3..a8512e2bf 100644 --- a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/YTest.java +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/YTest.java @@ -1,13 +1,12 @@ package org.arquillian.smart.testing.strategies.affected.fakeproject.test; -import org.arquillian.smart.testing.strategies.affected.Tests; +import org.arquillian.smart.testing.strategies.affected.ComponentUnderTest; import org.arquillian.smart.testing.strategies.affected.fakeproject.main.superbiz.Alone; import org.junit.Ignore; import org.junit.Test; -// Test ignored because it is used internally -@Ignore -@Tests(packagesOf = Alone.class) +@Ignore("Test ignored because it is used internally") +@ComponentUnderTest(packagesOf = Alone.class) public class YTest { @Test diff --git a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ZTest.java b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ZTest.java index 42633681f..fb505e816 100644 --- a/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ZTest.java +++ b/strategies/affected/src/test/java/org/arquillian/smart/testing/strategies/affected/fakeproject/test/ZTest.java @@ -1,13 +1,12 @@ package org.arquillian.smart.testing.strategies.affected.fakeproject.test; -import org.arquillian.smart.testing.strategies.affected.Tests; +import org.arquillian.smart.testing.strategies.affected.ComponentUnderTest; import org.junit.Ignore; import org.junit.Test; -// Test ignored because it is used internally -@Ignore +@Ignore("Test ignored because it is used internally") //tag::docs[] -@Tests(packages = "org.arquillian.smart.testing.strategies.affected.fakeproject.main.superbiz.*") +@ComponentUnderTest(packages = "org.arquillian.smart.testing.strategies.affected.fakeproject.main.superbiz.*") public class ZTest { //end::docs[] @Test