Skip to content

Commit 61411f1

Browse files
authored
better support for junit5 parameterised tests (via allure-framework#687)
1 parent d27d555 commit 61411f1

9 files changed

Lines changed: 498 additions & 35 deletions

File tree

allure-junit-platform/src/main/java/io/qameta/allure/junitplatform/AllureJunitPlatform.java

Lines changed: 96 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import io.qameta.allure.SeverityLevel;
2323
import io.qameta.allure.model.FixtureResult;
2424
import io.qameta.allure.model.Label;
25+
import io.qameta.allure.model.Parameter;
2526
import io.qameta.allure.model.Stage;
2627
import io.qameta.allure.model.Status;
2728
import io.qameta.allure.model.StatusDetails;
@@ -89,12 +90,18 @@
8990
})
9091
public class AllureJunitPlatform implements TestExecutionListener {
9192

93+
public static final String ALLURE_PARAMETER = "allure.parameter";
94+
public static final String ALLURE_PARAMETER_VALUE_KEY = "value";
95+
public static final String ALLURE_PARAMETER_MODE_KEY = "mode";
96+
public static final String ALLURE_PARAMETER_EXCLUDED_KEY = "excluded";
97+
9298
public static final String ALLURE_FIXTURE = "allure.fixture";
9399
public static final String PREPARE = "prepare";
94100
public static final String TEAR_DOWN = "tear_down";
95101
public static final String EVENT_START = "start";
96102
public static final String EVENT_STOP = "stop";
97103
public static final String EVENT_FAILURE = "failure";
104+
98105
public static final String JUNIT_PLATFORM_UNIQUE_ID = "junit.platform.uniqueid";
99106
private static final Logger LOGGER = LoggerFactory.getLogger(AllureJunitPlatform.class);
100107
private static final String STDOUT = "stdout";
@@ -188,40 +195,17 @@ public void executionSkipped(final TestIdentifier testIdentifier,
188195
);
189196
}
190197

191-
@SuppressWarnings({"ReturnCount", "PMD.NcssCount"})
198+
@SuppressWarnings({"ReturnCount", "PMD.NcssCount", "CyclomaticComplexity"})
192199
@Override
193200
public void reportingEntryPublished(final TestIdentifier testIdentifier,
194201
final ReportEntry entry) {
195202
final Map<String, String> keyValuePairs = entry.getKeyValuePairs();
196203
if (keyValuePairs.containsKey(ALLURE_FIXTURE)) {
197-
final String type = keyValuePairs.get(ALLURE_FIXTURE);
198-
final String event = keyValuePairs.get("event");
199-
200-
// skip for invalid events
201-
if (Objects.isNull(type) || Objects.isNull(event)) {
202-
return;
203-
}
204-
205-
switch (event) {
206-
case EVENT_START:
207-
final Optional<String> maybeParent = containers.get(testIdentifier);
208-
if (!maybeParent.isPresent()) {
209-
return;
210-
}
211-
final String parentUuid = maybeParent.get();
212-
startFixture(parentUuid, type, keyValuePairs);
213-
return;
214-
case EVENT_FAILURE:
215-
failFixture(keyValuePairs);
216-
resetContext(testIdentifier);
217-
return;
218-
case EVENT_STOP:
219-
stopFixture(keyValuePairs);
220-
resetContext(testIdentifier);
221-
return;
222-
default:
223-
break;
224-
}
204+
processFixtureEvent(testIdentifier, keyValuePairs);
205+
return;
206+
}
207+
if (keyValuePairs.containsKey(ALLURE_PARAMETER)) {
208+
processParameterEvent(keyValuePairs);
225209
return;
226210
}
227211

@@ -236,6 +220,63 @@ public void reportingEntryPublished(final TestIdentifier testIdentifier,
236220

237221
}
238222

223+
private void processParameterEvent(final Map<String, String> keyValuePairs) {
224+
final String name = keyValuePairs.get(ALLURE_PARAMETER);
225+
final String value = keyValuePairs.get(ALLURE_PARAMETER_VALUE_KEY);
226+
227+
final Parameter parameter = ResultsUtils.createParameter(name, value);
228+
if (keyValuePairs.containsKey(ALLURE_PARAMETER_MODE_KEY)) {
229+
final String modeString = keyValuePairs.get(ALLURE_PARAMETER_MODE_KEY);
230+
Stream.of(Parameter.Mode.values())
231+
.filter(mode -> mode.name().equalsIgnoreCase(modeString))
232+
.findAny()
233+
.ifPresent(parameter::setMode);
234+
}
235+
if (keyValuePairs.containsKey(ALLURE_PARAMETER_EXCLUDED_KEY)) {
236+
final String excludedString = keyValuePairs.get(ALLURE_PARAMETER_EXCLUDED_KEY);
237+
Optional.ofNullable(excludedString)
238+
.map(Boolean::parseBoolean)
239+
.ifPresent(parameter::setExcluded);
240+
}
241+
242+
getLifecycle().updateTestCase(tr -> tr.getParameters()
243+
.add(parameter)
244+
);
245+
}
246+
247+
@SuppressWarnings({"ReturnCount"})
248+
private void processFixtureEvent(final TestIdentifier testIdentifier,
249+
final Map<String, String> keyValuePairs) {
250+
final String type = keyValuePairs.get(ALLURE_FIXTURE);
251+
final String event = keyValuePairs.get("event");
252+
253+
// skip for invalid events
254+
if (Objects.isNull(type) || Objects.isNull(event)) {
255+
return;
256+
}
257+
258+
switch (event) {
259+
case EVENT_START:
260+
final Optional<String> maybeParent = containers.get(testIdentifier);
261+
if (!maybeParent.isPresent()) {
262+
return;
263+
}
264+
final String parentUuid = maybeParent.get();
265+
startFixture(parentUuid, type, keyValuePairs);
266+
return;
267+
case EVENT_FAILURE:
268+
failFixture(keyValuePairs);
269+
resetContext(testIdentifier);
270+
return;
271+
case EVENT_STOP:
272+
stopFixture(keyValuePairs);
273+
resetContext(testIdentifier);
274+
return;
275+
default:
276+
break;
277+
}
278+
}
279+
239280
private void resetContext(final TestIdentifier testIdentifier) {
240281
// in case of fixtures that reported within a test we need to return current
241282
// test case uuid to allure thread local storage
@@ -362,13 +403,38 @@ private void startTestCase(final TestIdentifier testIdentifier) {
362403
final Optional<Class<?>> testClass = testSource
363404
.flatMap(AllureJunitPlatformUtils::getTestClass);
364405

406+
final boolean testTemplate = "test-template-invocation"
407+
.equals(testIdentifier.getUniqueIdObject().getLastSegment().getType());
408+
409+
final Optional<TestIdentifier> maybeParent = Optional.of(testPlanStorage)
410+
.map(ThreadLocal::get)
411+
.flatMap(tp -> tp.getParent(testIdentifier));
412+
365413
final TestResult result = new TestResult()
366414
.setUuid(uuid)
367-
.setName(testIdentifier.getDisplayName())
415+
.setName(testTemplate && maybeParent.isPresent()
416+
? maybeParent.get().getDisplayName() + " " + testIdentifier.getDisplayName()
417+
: testIdentifier.getDisplayName()
418+
)
368419
.setLabels(getTags(testIdentifier))
420+
.setTestCaseId(testTemplate
421+
? maybeParent.map(TestIdentifier::getUniqueId)
422+
.orElseGet(testIdentifier::getUniqueId)
423+
: testIdentifier.getUniqueId()
424+
)
369425
.setHistoryId(getHistoryId(testIdentifier))
370426
.setStage(Stage.RUNNING);
371427

428+
if (testTemplate) {
429+
// history id is ignored in Allure TestOps, so we add a hidden parameter
430+
// to make sure different results are not considered as retries
431+
result.getParameters().add(new Parameter()
432+
.setMode(Parameter.Mode.HIDDEN)
433+
.setName("UniqueId")
434+
.setValue(testIdentifier.getUniqueId())
435+
);
436+
}
437+
372438
result.getLabels().addAll(getProvidedLabels());
373439

374440
result.getLabels().add(getJUnitPlatformUniqueId(testIdentifier));

allure-junit-platform/src/test/java/io/qameta/allure/junitplatform/AllureJunitPlatformTest.java

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@
3232
import io.qameta.allure.junitplatform.features.OwnerTest;
3333
import io.qameta.allure.junitplatform.features.ParallelTests;
3434
import io.qameta.allure.junitplatform.features.ParameterisedTests;
35+
import io.qameta.allure.junitplatform.features.ParameterisedTestsWithDisplayName;
3536
import io.qameta.allure.junitplatform.features.PassedTests;
3637
import io.qameta.allure.junitplatform.features.RepeatedTests;
38+
import io.qameta.allure.junitplatform.features.ReportEntryParameter;
3739
import io.qameta.allure.junitplatform.features.SeverityTest;
3840
import io.qameta.allure.junitplatform.features.SkippedInBeforeAllTests;
3941
import io.qameta.allure.junitplatform.features.SkippedTests;
@@ -53,6 +55,7 @@
5355
import io.qameta.allure.model.Attachment;
5456
import io.qameta.allure.model.Label;
5557
import io.qameta.allure.model.Link;
58+
import io.qameta.allure.model.Parameter;
5659
import io.qameta.allure.model.Stage;
5760
import io.qameta.allure.model.Status;
5861
import io.qameta.allure.model.StatusDetails;
@@ -209,9 +212,9 @@ void shouldProcessBrokenInAfterAllTests() {
209212
tr -> Optional.of(tr).map(TestResult::getStatusDetails).map(StatusDetails::getMessage).orElse(null))
210213
.containsExactlyInAnyOrder(
211214
tuple("BrokenInAfterAllTests", Status.BROKEN, "Exception in @AfterAll"),
212-
tuple("[1] value=a", Status.PASSED, null),
213-
tuple("[2] value=b", Status.PASSED, null),
214-
tuple("[3] value=c", Status.PASSED, null),
215+
tuple("parameterisedTest(String) [1] value=a", Status.PASSED, null),
216+
tuple("parameterisedTest(String) [2] value=b", Status.PASSED, null),
217+
tuple("parameterisedTest(String) [3] value=c", Status.PASSED, null),
215218
tuple("test1()", Status.PASSED, null),
216219
tuple("test2()", Status.PASSED, null)
217220
);
@@ -323,7 +326,10 @@ void shouldProcessParametrisedTests() {
323326
.hasSize(2)
324327
.filteredOn(hasStatus(Status.PASSED))
325328
.flatExtracting(TestResult::getName)
326-
.containsExactlyInAnyOrder("[1] argument=Hello", "[2] argument=World");
329+
.containsExactlyInAnyOrder(
330+
"testWithStringParameter(String) [1] argument=Hello",
331+
"testWithStringParameter(String) [2] argument=World"
332+
);
327333
}
328334

329335
@Test
@@ -773,4 +779,51 @@ void shouldPopulateTestCaseId() {
773779
.first()
774780
.isEqualTo("[engine:junit-jupiter]/[class:io.qameta.allure.junitplatform.features.JupiterUniqueIdTest]/[method:jupiterTest()]");
775781
}
782+
783+
@AllureFeatures.Parameters
784+
@Test
785+
void shouldAllowUsageOfDisplayForParameterisedTests() {
786+
final AllureResults results = runClasses(ParameterisedTestsWithDisplayName.class);
787+
final List<TestResult> testResults = results.getTestResults();
788+
assertThat(testResults)
789+
.extracting(
790+
TestResult::getName
791+
)
792+
.containsExactlyInAnyOrder(
793+
"Second Test [1] value=a",
794+
"Second Test [2] value=b"
795+
);
796+
}
797+
798+
@AllureFeatures.Parameters
799+
@Test
800+
void shouldProcessAllureParameterReportingEvents() {
801+
final AllureResults results = runClasses(ReportEntryParameter.class);
802+
final List<TestResult> testResults = results.getTestResults();
803+
assertThat(testResults)
804+
.filteredOn("name", "simpleParameterEvent(TestReporter)")
805+
.flatExtracting(TestResult::getParameters)
806+
.extracting(Parameter::getName, Parameter::getValue, Parameter::getMode, Parameter::getExcluded)
807+
.containsExactlyInAnyOrder(
808+
tuple("some parameter name", "some parameter value", null, null)
809+
);
810+
assertThat(testResults)
811+
.filteredOn("name", "multipleParameterEvent(TestReporter)")
812+
.flatExtracting(TestResult::getParameters)
813+
.extracting(Parameter::getName, Parameter::getValue, Parameter::getMode, Parameter::getExcluded)
814+
.containsExactlyInAnyOrder(
815+
tuple("first name", "first value", null, null),
816+
tuple("second name", "second value", null, null),
817+
tuple("third name", "third value", null, null)
818+
);
819+
assertThat(testResults)
820+
.filteredOn("name", "modeAndExcluded(TestReporter)")
821+
.flatExtracting(TestResult::getParameters)
822+
.extracting(Parameter::getName, Parameter::getValue, Parameter::getMode, Parameter::getExcluded)
823+
.containsExactlyInAnyOrder(
824+
tuple("hidden excluded", "hidden excluded value", Parameter.Mode.HIDDEN, true),
825+
tuple("default excluded", "default excluded value", Parameter.Mode.DEFAULT, true),
826+
tuple("masked not excluded", "masked not excluded value", Parameter.Mode.MASKED, false)
827+
);
828+
}
776829
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2019 Qameta Software OÜ
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.qameta.allure.junitplatform.features;
17+
18+
import org.junit.jupiter.api.DisplayName;
19+
import org.junit.jupiter.params.ParameterizedTest;
20+
import org.junit.jupiter.params.provider.ValueSource;
21+
22+
/**
23+
* @author charlie (Dmitry Baev).
24+
*/
25+
public class ParameterisedTestsWithDisplayName {
26+
27+
@DisplayName("Second Test")
28+
@ParameterizedTest
29+
@ValueSource(strings = {"a", "b"})
30+
void first(String value) {
31+
}
32+
33+
}

0 commit comments

Comments
 (0)