Skip to content

Use snapshot-tests to ease adapting assertions after changes to starter #4310

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

Merged
merged 2 commits into from
Feb 11, 2025
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ coverage.db*
/.tool-versions

checksums*

# snapshot-tests
*.snapshot_actual
*.snapshot_raw
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ logback = "1.5.16"
mockito = "5.15.2"
opentest4j = "1.3.0"
openTestReporting = "0.2.0-M2"
snapshotTests = "1.11.0"
surefire = "3.5.2"
xmlunit = "2.10.0"

Expand Down Expand Up @@ -64,6 +65,8 @@ openTestReporting-tooling-core = { module = "org.opentest4j.reporting:open-test-
openTestReporting-tooling-spi = { module = "org.opentest4j.reporting:open-test-reporting-tooling-spi", version.ref = "openTestReporting" }
picocli = { module = "info.picocli:picocli", version = "4.7.6" }
slf4j-julBinding = { module = "org.slf4j:slf4j-jdk14", version = "2.0.16" }
snapshotTests-junit5 = { module = "de.skuzzle.test:snapshot-tests-junit5", version.ref = "snapshotTests" }
snapshotTests-xml = { module = "de.skuzzle.test:snapshot-tests-xml", version.ref = "snapshotTests" }
spock1 = { module = "org.spockframework:spock-core", version = "1.3-groovy-2.5" }
univocity-parsers = { module = "com.sonofab1rd:univocity-parsers", version = "2.10.1" }
xmlunit-assertj = { module = "org.xmlunit:xmlunit-assertj3", version.ref = "xmlunit" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ dependencies {
testImplementation(libs.bundles.xmlunit)
testImplementation(testFixtures(projects.junitJupiterApi))
testImplementation(testFixtures(projects.junitPlatformReporting))
testImplementation(libs.snapshotTests.junit5)
testImplementation(libs.snapshotTests.xml)

thirdPartyJars(libs.junit4)
thirdPartyJars(libs.assertj)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
import java.nio.file.Path;
import java.util.List;

import de.skuzzle.test.snapshots.Snapshot;
import de.skuzzle.test.snapshots.junit5.EnableSnapshotTests;

import org.apache.tools.ant.Main;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
Expand All @@ -29,11 +32,14 @@
/**
* @since 1.3
*/
@EnableSnapshotTests
class AntStarterTests {

@Test
@Timeout(60)
void ant_starter(@TempDir Path workspace, @FilePrefix("ant") OutputFiles outputFiles) throws Exception {
void ant_starter(@TempDir Path workspace, @FilePrefix("ant") OutputFiles outputFiles, Snapshot snapshot)
throws Exception {

var result = ProcessStarters.java() //
.workingDir(copyToWorkspace(Projects.JUPITER_STARTER, workspace)) //
.addArguments("-cp", System.getProperty("antJars"), Main.class.getName()) //
Expand All @@ -57,6 +63,6 @@ void ant_starter(@TempDir Path workspace, @FilePrefix("ant") OutputFiles outputF
result.stdOutLines());

var testResultsDir = workspace.resolve("build/test-report");
verifyContainsExpectedStartedOpenTestReport(testResultsDir);
verifyContainsExpectedStartedOpenTestReport(testResultsDir, snapshot);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

import java.nio.file.Path;

import de.skuzzle.test.snapshots.Snapshot;
import de.skuzzle.test.snapshots.junit5.EnableSnapshotTests;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.platform.tests.process.OutputFiles;
Expand All @@ -30,10 +33,13 @@
/**
* @since 1.3
*/
@EnableSnapshotTests
class GradleStarterTests {

@Test
void gradle_wrapper(@TempDir Path workspace, @FilePrefix("gradle") OutputFiles outputFiles) throws Exception {
void gradle_wrapper(@TempDir Path workspace, @FilePrefix("gradle") OutputFiles outputFiles, Snapshot snapshot)
throws Exception {

var result = ProcessStarters.gradlew() //
.workingDir(copyToWorkspace(Projects.JUPITER_STARTER, workspace)) //
.addArguments("-Dmaven.repo=" + MavenRepo.dir()) //
Expand All @@ -47,6 +53,6 @@ void gradle_wrapper(@TempDir Path workspace, @FilePrefix("gradle") OutputFiles o
assertThat(result.stdOut()).contains("Using Java version: 1.8");

var testResultsDir = workspace.resolve("build/test-results/test");
verifyContainsExpectedStartedOpenTestReport(testResultsDir);
verifyContainsExpectedStartedOpenTestReport(testResultsDir, snapshot);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

import java.nio.file.Path;

import de.skuzzle.test.snapshots.Snapshot;
import de.skuzzle.test.snapshots.junit5.EnableSnapshotTests;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.platform.tests.process.OutputFiles;
Expand All @@ -30,6 +33,7 @@
/**
* @since 1.3
*/
@EnableSnapshotTests
class MavenStarterTests {

@ManagedResource
Expand All @@ -39,8 +43,9 @@ class MavenStarterTests {
MavenRepoProxy mavenRepoProxy;

@Test
void verifyJupiterStarterProject(@TempDir Path workspace, @FilePrefix("maven") OutputFiles outputFiles)
throws Exception {
void verifyJupiterStarterProject(@TempDir Path workspace, @FilePrefix("maven") OutputFiles outputFiles,
Snapshot snapshot) throws Exception {

var result = ProcessStarters.maven(Helper.getJavaHome("8").orElseThrow(TestAbortedException::new)) //
.workingDir(copyToWorkspace(Projects.JUPITER_STARTER, workspace)) //
.addArguments(localMavenRepo.toCliArgument(), "-Dmaven.repo=" + MavenRepo.dir()) //
Expand All @@ -56,6 +61,6 @@ void verifyJupiterStarterProject(@TempDir Path workspace, @FilePrefix("maven") O
assertThat(result.stdOut()).contains("Using Java version: 1.8");

var testResultsDir = workspace.resolve("target/surefire-reports");
verifyContainsExpectedStartedOpenTestReport(testResultsDir);
verifyContainsExpectedStartedOpenTestReport(testResultsDir, snapshot);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,147 +10,73 @@

package platform.tooling.support.tests;

import static de.skuzzle.test.snapshots.data.xml.XmlSnapshot.xml;
import static org.junit.platform.reporting.testutil.FileUtils.findPath;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.function.UnaryOperator;
import java.util.regex.Pattern;

import org.xmlunit.assertj3.XmlAssert;
import org.xmlunit.placeholder.PlaceholderDifferenceEvaluator;
import de.skuzzle.test.snapshots.Snapshot;
import de.skuzzle.test.snapshots.SnapshotSerializer;
import de.skuzzle.test.snapshots.StructuredData;
import de.skuzzle.test.snapshots.StructuredDataProvider;

class XmlAssertions {

static void verifyContainsExpectedStartedOpenTestReport(Path testResultsDir) {
static void verifyContainsExpectedStartedOpenTestReport(Path testResultsDir, Snapshot snapshot) throws IOException {
var xmlFile = findPath(testResultsDir, "glob:**/open-test-report.xml");
verifyContent(xmlFile);
verifyContent(xmlFile, snapshot);
}

private static void verifyContent(Path xmlFile) {
var expected = """
<e:events xmlns="https://schemas.opentest4j.org/reporting/core/0.2.0"
xmlns:e="https://schemas.opentest4j.org/reporting/events/0.2.0"
xmlns:git="https://schemas.opentest4j.org/reporting/git/0.2.0"
xmlns:java="https://schemas.opentest4j.org/reporting/java/0.2.0"
xmlns:junit="https://schemas.junit.org/open-test-reporting"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://schemas.junit.org/open-test-reporting https://junit.org/junit5/schemas/open-test-reporting/junit-1.9.xsd">
<infrastructure>
<hostName>${xmlunit.ignore}</hostName>
<userName>${xmlunit.ignore}</userName>
<operatingSystem>${xmlunit.ignore}</operatingSystem>
<cpuCores>${xmlunit.ignore}</cpuCores>
<java:javaVersion>${xmlunit.ignore}</java:javaVersion>
<java:fileEncoding>${xmlunit.ignore}</java:fileEncoding>
<java:heapSize max="${xmlunit.isNumber}"/>
</infrastructure>
<e:started id="1" name="JUnit Jupiter" time="${xmlunit.isDateTime}">
<metadata>
<junit:uniqueId>[engine:junit-jupiter]</junit:uniqueId>
<junit:legacyReportingName>JUnit Jupiter</junit:legacyReportingName>
<junit:type>CONTAINER</junit:type>
</metadata>
</e:started>
<e:started id="2" name="CalculatorTests" parentId="1" time="${xmlunit.isDateTime}">
<metadata>
<junit:uniqueId>[engine:junit-jupiter]/[class:com.example.project.CalculatorTests]</junit:uniqueId>
<junit:legacyReportingName>com.example.project.CalculatorTests</junit:legacyReportingName>
<junit:type>CONTAINER</junit:type>
</metadata>
<sources>
<java:classSource className="com.example.project.CalculatorTests"/>
</sources>
</e:started>
<e:started id="3" name="1 + 1 = 2" parentId="2" time="${xmlunit.isDateTime}">
<metadata>
<junit:uniqueId>[engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[method:addsTwoNumbers()]</junit:uniqueId>
<junit:legacyReportingName>addsTwoNumbers()</junit:legacyReportingName>
<junit:type>TEST</junit:type>
</metadata>
<sources>
<java:methodSource className="com.example.project.CalculatorTests" methodName="addsTwoNumbers" methodParameterTypes=""/>
</sources>
</e:started>
<e:finished id="3" time="${xmlunit.isDateTime}">
<result status="SUCCESSFUL"/>
</e:finished>
<e:started id="4" name="add(int, int, int)" parentId="2" time="${xmlunit.isDateTime}">
<metadata>
<junit:uniqueId>[engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]</junit:uniqueId>
<junit:legacyReportingName>add(int, int, int)</junit:legacyReportingName>
<junit:type>CONTAINER</junit:type>
</metadata>
<sources>
<java:methodSource className="com.example.project.CalculatorTests" methodName="add" methodParameterTypes="int, int, int"/>
</sources>
</e:started>
<e:started id="5" name="0 + 1 = 1" parentId="4" time="${xmlunit.isDateTime}">
<metadata>
<junit:uniqueId>[engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#1]</junit:uniqueId>
<junit:legacyReportingName>add(int, int, int)[1]</junit:legacyReportingName>
<junit:type>TEST</junit:type>
</metadata>
<sources>
<java:methodSource className="com.example.project.CalculatorTests" methodName="add" methodParameterTypes="int, int, int"/>
</sources>
</e:started>
<e:finished id="5" time="${xmlunit.isDateTime}">
<result status="SUCCESSFUL"/>
</e:finished>
<e:started id="6" name="1 + 2 = 3" parentId="4" time="${xmlunit.isDateTime}">
<metadata>
<junit:uniqueId>[engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#2]</junit:uniqueId>
<junit:legacyReportingName>add(int, int, int)[2]</junit:legacyReportingName>
<junit:type>TEST</junit:type>
</metadata>
<sources>
<java:methodSource className="com.example.project.CalculatorTests" methodName="add" methodParameterTypes="int, int, int"/>
</sources>
</e:started>
<e:finished id="6" time="${xmlunit.isDateTime}">
<result status="SUCCESSFUL"/>
</e:finished>
<e:started id="7" name="49 + 51 = 100" parentId="4" time="${xmlunit.isDateTime}">
<metadata>
<junit:uniqueId>[engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#3]</junit:uniqueId>
<junit:legacyReportingName>add(int, int, int)[3]</junit:legacyReportingName>
<junit:type>TEST</junit:type>
</metadata>
<sources>
<java:methodSource className="com.example.project.CalculatorTests" methodName="add" methodParameterTypes="int, int, int"/>
</sources>
</e:started>
<e:finished id="7" time="${xmlunit.isDateTime}">
<result status="SUCCESSFUL"/>
</e:finished>
<e:started id="8" name="1 + 100 = 101" parentId="4" time="${xmlunit.isDateTime}">
<metadata>
<junit:uniqueId>[engine:junit-jupiter]/[class:com.example.project.CalculatorTests]/[test-template:add(int, int, int)]/[test-template-invocation:#4]</junit:uniqueId>
<junit:legacyReportingName>add(int, int, int)[4]</junit:legacyReportingName>
<junit:type>TEST</junit:type>
</metadata>
<sources>
<java:methodSource className="com.example.project.CalculatorTests" methodName="add" methodParameterTypes="int, int, int"/>
</sources>
</e:started>
<e:finished id="8" time="${xmlunit.isDateTime}">
<result status="SUCCESSFUL"/>
</e:finished>
<e:finished id="4" time="${xmlunit.isDateTime}">
<result status="SUCCESSFUL"/>
</e:finished>
<e:finished id="2" time="${xmlunit.isDateTime}">
<result status="SUCCESSFUL"/>
</e:finished>
<e:finished id="1" time="${xmlunit.isDateTime}">
<result status="SUCCESSFUL"/>
</e:finished>
</e:events>
""";
private static void verifyContent(Path xmlFile, Snapshot snapshot) throws IOException {
snapshot.named("open-test-report.xml") //
.assertThat(Files.readString(xmlFile)) //
.as(obfuscated( //
xml() //
.withXPathNamespaceContext(Map.of( //
"c", "https://schemas.opentest4j.org/reporting/core/0.2.0", //
"e", "https://schemas.opentest4j.org/reporting/events/0.2.0", //
"java", "https://schemas.opentest4j.org/reporting/java/0.2.0" //
)) //
.withComparisonRules(rules -> rules //
.pathAt("//@time").mustMatch(
Pattern.compile("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?Z")) //
.pathAt("//c:infrastructure/c:hostName/text()").ignore() //
.pathAt("//c:infrastructure/c:userName/text()").ignore() //
.pathAt("//c:infrastructure/c:operatingSystem/text()").ignore() //
.pathAt("//c:infrastructure/c:cpuCores/text()").ignore() //
.pathAt("//c:infrastructure/java:javaVersion/text()").ignore() //
.pathAt("//c:infrastructure/java:fileEncoding/text()").ignore() //
.pathAt("//c:infrastructure/java:heapSize/@max").ignore() //
), //
text -> text //
.replaceAll("<hostName>.+?</hostName>", "<hostName>obfuscated</hostName>") //
.replaceAll("<userName>.+?</userName>", "<userName>obfuscated</userName>") //
)) //
.matchesSnapshotStructure();
}

private static StructuredDataProvider obfuscated(StructuredDataProvider provider,
UnaryOperator<String> obfuscator) {
return () -> {
var structuredData = provider.build();
var snapshotSerializer = obfuscatingSnapshotSerializer(structuredData.snapshotSerializer(), obfuscator);
return StructuredData.with(snapshotSerializer, structuredData.structuralAssertions());
};
}

XmlAssert.assertThat(xmlFile).and(expected) //
.withDifferenceEvaluator(new PlaceholderDifferenceEvaluator(Pattern.quote("${"), Pattern.quote("}"),
Pattern.quote("#"), Pattern.quote("#"), ",")) //
.ignoreWhitespace() //
.areIdentical();
private static SnapshotSerializer obfuscatingSnapshotSerializer(SnapshotSerializer delegate,
UnaryOperator<String> obfuscator) {
return testResult -> {
Object obfuscatedTestResult = testResult;
if (testResult instanceof String) {
obfuscatedTestResult = obfuscator.apply((String) testResult);
}
return delegate.serialize(obfuscatedTestResult);
};
}
}
Loading
Loading