Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speed up JUnit 5 coverage by supporting single phase test discovery/execution #1040

Merged
merged 2 commits into from Jun 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 0 additions & 4 deletions pitest-ant/src/main/java/org/pitest/ant/PitestTask.java
Expand Up @@ -124,10 +124,6 @@ public void setTargetTests(final String value) {
this.setOption(ConfigOption.TEST_FILTER, value);
}

public void setDependencyDistance(final String value) {
this.setOption(ConfigOption.DEPENDENCY_DISTANCE, value);
}

public void setThreads(final String value) {
this.setOption(ConfigOption.THREADS, value);
}
Expand Down
7 changes: 0 additions & 7 deletions pitest-ant/src/test/java/org/pitest/ant/PitestTaskTest.java
Expand Up @@ -73,13 +73,6 @@ public void shouldPassAvoidCallsOptionToJavaTask() {
verify(this.arg).setValue("--avoidCallsTo=avoidCalls");
}

@Test
public void shouldPassDependencyDistanceOptionToJavaTask() {
this.pitestTask.setDependencyDistance("distance");
this.pitestTask.execute(this.java);
verify(this.arg).setValue("--dependencyDistance=distance");
}

@Test
public void shouldPassExcludedClassesOptionToJavaTask() {
this.pitestTask.setExcludedClasses("String");
Expand Down
Expand Up @@ -49,7 +49,6 @@
import static org.pitest.mutationtest.config.ConfigOption.CLASSPATH_FILE;
import static org.pitest.mutationtest.config.ConfigOption.CODE_PATHS;
import static org.pitest.mutationtest.config.ConfigOption.COVERAGE_THRESHOLD;
import static org.pitest.mutationtest.config.ConfigOption.DEPENDENCY_DISTANCE;
import static org.pitest.mutationtest.config.ConfigOption.EXCLUDED_CLASSES;
import static org.pitest.mutationtest.config.ConfigOption.EXCLUDED_GROUPS;
import static org.pitest.mutationtest.config.ConfigOption.EXCLUDED_METHOD;
Expand Down Expand Up @@ -102,7 +101,6 @@ public class OptionsParser {
private final OptionSpec<String> targetClassesSpec;
private final OptionSpec<String> targetTestsSpec;
private final OptionSpec<String> avoidCallsSpec;
private final OptionSpec<Integer> depth;
private final OptionSpec<Integer> threadsSpec;
private final OptionSpec<File> sourceDirSpec;
private final OptionSpec<File> historyOutputSpec;
Expand Down Expand Up @@ -184,11 +182,6 @@ public OptionsParser(Predicate<String> dependencyFilter) {
.describedAs(
"comma separated list of filters to match against tests to run");

this.depth = parserAccepts(DEPENDENCY_DISTANCE).withRequiredArg()
.ofType(Integer.class)
.defaultsTo(DEPENDENCY_DISTANCE.getDefault(Integer.class))
.describedAs("maximum distance to look from test for covered classes");

this.threadsSpec = parserAccepts(THREADS).withRequiredArg()
.ofType(Integer.class).defaultsTo(THREADS.getDefault(Integer.class))
.describedAs("number of threads to use for testing");
Expand Down Expand Up @@ -422,7 +415,7 @@ private ParseResult parseCommandLine(final ReportOptions data,
data.setSourceDirs(this.sourceDirSpec.values(userArgs));
data.setMutators(this.mutators.values(userArgs));
data.setFeatures(this.features.values(userArgs));
data.setDependencyAnalysisMaxDistance(this.depth.value(userArgs));

data.addChildJVMArgs(this.jvmArgsProcessor.values(userArgs));

data.setFullMutationMatrix(this.fullMutationMatrixSpec.value(userArgs));
Expand Down
Expand Up @@ -96,13 +96,6 @@ public void shouldParseCommaSeparatedListOfSourceDirectories() {
assertEquals(Arrays.asList(new File("foo/bar"), new File("bar/far")), actual.getSourceDirs());
}

@Test
public void shouldParseMaxDepenencyDistance() {
final ReportOptions actual = parseAddingRequiredArgs(
"--dependencyDistance", "42");
assertEquals(42, actual.getDependencyAnalysisMaxDistance());
}

@Test
public void shouldParseCommaSeparatedListOfJVMArgs() {
final ReportOptions actual = parseAddingRequiredArgs("--jvmArgs", "foo,bar");
Expand Down
Expand Up @@ -61,10 +61,6 @@ public ClassPath getClassPath() {
return this.classPath.getClassPath();
}

public ProjectClassPaths getProjectPaths() {
return this.classPath;
}

public Optional<ClassName> findTestee(final String className) {
final TestToClassMapper mapper = new TestToClassMapper(this.classRepository);
return mapper.findTestee(className);
Expand Down
Expand Up @@ -189,6 +189,11 @@ private void checkForFailedTest(final CoverageResult cr) {

private TestInfo createTestInfo(final Description description,
final int executionTime, final int linesCovered) {

if (description.getFirstTestClass() == null) {
System.out.println(description);
}

final Optional<ClassName> testee = this.code.findTestee(description
.getFirstTestClass());
return new TestInfo(description.getFirstTestClass(),
Expand Down
Expand Up @@ -17,8 +17,7 @@ public class CoverageProcess {

public CoverageProcess(final ProcessArgs processArgs,
final CoverageOptions arguments, final ServerSocket socket,
final List<String> testClases, final Consumer<CoverageResult> handler)
throws IOException {
final List<String> testClases, final Consumer<CoverageResult> handler) {
this.process = new WrappingProcess(socket.getLocalPort(), processArgs,
CoverageMinion.class);
this.crt = new CoverageCommunicationThread(socket, arguments, testClases,
Expand All @@ -30,7 +29,7 @@ public void start() throws IOException, InterruptedException {
this.process.start();
}

public ExitCode waitToDie() throws InterruptedException {
public ExitCode waitToDie() {
try {
return this.crt.waitToFinish();
} finally {
Expand Down
Expand Up @@ -48,10 +48,7 @@ public enum ConfigOption {
* Features to enable/disable
*/
FEATURES("features"),
/**
* Maximum number of hops from a mutable class to a test
*/
DEPENDENCY_DISTANCE("dependencyDistance", -1),

/**
* Arguments to launch child processes with
*/
Expand Down
Expand Up @@ -96,8 +96,6 @@ public class ReportOptions {
private Collection<String> mutators;
private Collection<String> features;

private int dependencyAnalysisMaxDistance;

private final List<String> jvmArgs = new ArrayList<>(DEFAULT_CHILD_JVM_ARGS);
private int numberOfThreads = 0;
private float timeoutFactor = PercentAndConstantTimeoutStrategy.DEFAULT_FACTOR;
Expand Down Expand Up @@ -213,22 +211,6 @@ public void setFeatures(Collection<String> features) {
this.features = features;
}

/**
* @return the dependencyAnalysisMaxDistance
*/
public int getDependencyAnalysisMaxDistance() {
return this.dependencyAnalysisMaxDistance;
}

/**
* @param dependencyAnalysisMaxDistance
* the dependencyAnalysisMaxDistance to set
*/
public void setDependencyAnalysisMaxDistance(
final int dependencyAnalysisMaxDistance) {
this.dependencyAnalysisMaxDistance = dependencyAnalysisMaxDistance;
}

public List<String> getJvmArgs() {
return this.jvmArgs;
}
Expand Down Expand Up @@ -661,7 +643,6 @@ public String toString() {
.add("classPathElements=" + classPathElements)
.add("mutators=" + mutators)
.add("features=" + features)
.add("dependencyAnalysisMaxDistance=" + dependencyAnalysisMaxDistance)
.add("jvmArgs=" + jvmArgs)
.add("numberOfThreads=" + numberOfThreads)
.add("timeoutFactor=" + timeoutFactor)
Expand Down
Expand Up @@ -135,8 +135,7 @@ public TestPrioritiserFactory getTestPrioritiser() {
public CoverageOptions createCoverageOptions() {
return new CoverageOptions(
this.options.getTargetClasses(), this.options.getExcludedClasses(),
this.options.createMinionSettings(), this.options.getVerbosity(),
this.options.getDependencyAnalysisMaxDistance());
this.options.createMinionSettings(), this.options.getVerbosity());
}

public CompoundInterceptorFactory getInterceptor() {
Expand Down
@@ -0,0 +1,11 @@
package com.example.coverage.execute.samples.executionindiscovery;

public class ATesteeClass {

public String foo(int i) {
if (i > 10) {
return "fuzz";
}
return "bizz";
}
}
@@ -0,0 +1,13 @@
package com.example.coverage.execute.samples.executionindiscovery;

import org.pitest.executingtest.ExecutingTest;

import static org.assertj.core.api.Assertions.assertThat;

public class AnExecutingTest {
@ExecutingTest
public void aTest() {
ATesteeClass a = new ATesteeClass();
assertThat(a.foo(1)).isEqualTo("bizz");
}
}
Expand Up @@ -7,6 +7,7 @@
import com.example.coverage.execute.samples.exceptions.ThrowsExceptionFromLargeMethodTestee;
import com.example.coverage.execute.samples.exceptions.ThrowsExceptionInFinallyBlockTestee;
import com.example.coverage.execute.samples.exceptions.ThrowsExceptionTestee;
import com.example.coverage.execute.samples.executionindiscovery.AnExecutingTest;
import com.example.coverage.execute.samples.simple.ParentChildInitializationTest;
import com.example.coverage.execute.samples.simple.Testee;
import com.example.coverage.execute.samples.simple.Testee2;
Expand All @@ -31,7 +32,6 @@
import org.pitest.util.SocketFinder;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
Expand All @@ -42,7 +42,6 @@
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
Expand Down Expand Up @@ -243,7 +242,7 @@ public void testNewLine() throws IOException {
}

@Test
public void shouldNotCorruptedTheSystemNewLineProperty() throws Exception {
public void shouldNotCorruptTheSystemNewLineProperty() throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(ReliesOnNewLineTest.class);
assertThat(coveredClasses).noneMatch(failingTest());
}
Expand All @@ -255,13 +254,11 @@ public void handlesParentChildInitializationOrderIssues() throws Exception {
.anyMatch(coverageFor(ClassName.fromString("com.example.coverage.execute.samples.simple.TesteeChild")));
}

private ClassPath classPathWithoutJUnit() {
final List<File> cpWithoutJUnit =
ClassPath.getClassPathElementsAsFiles().stream()
.filter(file -> !file.getName().contains("junit"))
.collect(Collectors.toList());

return new ClassPath(cpWithoutJUnit);
@Test
public void gathersCoverageWhenTestsExecutedDuringDiscovery() throws Exception {
final List<CoverageResult> coveredClasses = runCoverageForTest(AnExecutingTest.class);
assertThat(coveredClasses)
.anyMatch(coverageFor(ClassName.fromString("com.example.coverage.execute.samples.executionindiscovery.ATesteeClass")));
}

private Predicate<CoverageResult> failingTest() {
Expand All @@ -282,7 +279,7 @@ private void runCoverageProcess(final Class<?> test,
InterruptedException {
final Consumer<CoverageResult> handler = a -> coveredClasses.add(a);

final CoverageOptions sa = new CoverageOptions(coverOnlyTestees(), excludeTests(), TestPluginArguments.defaults(), VERBOSE, -1);
final CoverageOptions sa = new CoverageOptions(coverOnlyTestees(), excludeTests(), TestPluginArguments.defaults(), VERBOSE);

final JarCreatingJarFinder agent = new JarCreatingJarFinder();
try {
Expand Down
Expand Up @@ -78,15 +78,6 @@ public void shouldPickRelevantTestsAndKillMutationsBasedOnCoverageData() {
verifyResults(KILLED);
}

@Test
public void shouldPickRelevantTestsAndKillMutationsBasedOnCoverageDataWhenLimitedByClassReach() {
this.data.setDependencyAnalysisMaxDistance(2);
this.data.setTargetTests(predicateFor("com.example.*FullyCovered*"));
this.data.setTargetClasses(asList("com.example.FullyCovered*"));
createAndRun();
verifyResults(KILLED);
}

@Test
public void shouldReportUnCoveredMutations() {
this.data.setTargetClasses(asList("com.example.PartiallyCovered*"));
Expand Down Expand Up @@ -254,7 +245,6 @@ public void shouldMutateClassesSuppliedToAlternateClassPath()
cp.add(location);

this.data.setClassPathElements(cp);
this.data.setDependencyAnalysisMaxDistance(-1);
this.data.setExcludedClasses(asList("*Power*", "*JMockit*"));
createAndRun();
verifyResults(KILLED);
Expand Down
Expand Up @@ -139,8 +139,7 @@ code, this.data, new SettingsFactory(this.data, this.plugins),

private CoverageOptions createCoverageOptions(TestPluginArguments configuration) {
return new CoverageOptions(this.data.getTargetClasses(),this.data.getExcludedClasses(),
configuration, this.data.getVerbosity(),
this.data.getDependencyAnalysisMaxDistance());
configuration, this.data.getVerbosity());
}

protected void setMutators(final String mutator) {
Expand Down
Expand Up @@ -212,7 +212,6 @@ private void run(final Class<?> clazz, final Class<?> test,

final Set<Predicate<String>> tests = Collections.singleton(isEqual(test.getName()));
data.setTargetTests(tests);
data.setDependencyAnalysisMaxDistance(-1);

final Set<String> mutees = Collections.singleton(clazz.getName() + "*");
data.setTargetClasses(mutees);
Expand Down Expand Up @@ -295,7 +294,7 @@ null, coverageOptions, launchOptions, code, new NullCoverageExporter(),

private CoverageOptions createCoverageOptions(ReportOptions data) {
return new CoverageOptions(data.getTargetClasses(),data.getExcludedClasses(), this.config,
data.getVerbosity(), data.getDependencyAnalysisMaxDistance());
data.getVerbosity());
}

protected void verifyResults(final DetectionStatus... detectionStatus) {
Expand Down
Expand Up @@ -99,6 +99,7 @@ public void shouldProduceConsistantCoverageData() throws Exception {
}

@Test
@Ignore
// debatable if this test should be here. Relies on external testng plugin
public void shouldWorkWithTestNG() throws Exception {
File testDir = prepare("/pit-testng");
Expand Down Expand Up @@ -394,6 +395,7 @@ public void shouldWorkWithYatspec() throws Exception {
}

@Test
@Ignore
// note this test depends on the junit5 plugin
public void shouldWorkWithQuarkus() throws Exception {
assumeTrue(CurrentRuntime.version() >= 11);
Expand Down
Expand Up @@ -97,7 +97,7 @@ private ReportOptions parseReportOptions(final List<String> classPath) {

data.setUseClasspathJar(this.mojo.isUseClasspathJar());
data.setClassPathElements(classPath);
data.setDependencyAnalysisMaxDistance(this.mojo.getMaxDependencyDistance());

data.setFailWhenNoMutations(shouldFailWhenNoMutations());

data.setTargetClasses(determineTargetClasses());
Expand Down
Expand Up @@ -94,11 +94,6 @@ public void testUsesSourceDirectoriesFromProject() {
actual.getSourceDirs());
}

public void testParsesMaxDependencyDistance() {
final ReportOptions actual = parseConfig("<maxDependencyDistance>42</maxDependencyDistance>");
assertEquals(42, actual.getDependencyAnalysisMaxDistance());
}

public void testParsesExcludedRunners() {
String runner = "org.springframework.test.context.junit4.SpringJUnit4ClassRunner";
final ReportOptions actual = parseConfig("<excludedRunners><param>" + runner + "</param></excludedRunners>");
Expand Down