Skip to content

Commit 0b44973

Browse files
authored
support inherited and configurable testng instance parameters (via #1321)
1 parent abdb58b commit 0b44973

6 files changed

Lines changed: 213 additions & 5 deletions

File tree

allure-testng/src/main/java/io/qameta/allure/testng/AllureTestNg.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,7 @@ protected String getHistoryId(final ITestNGMethod method, final List<Parameter>
902902
digest.update(testClassName.getBytes(UTF_8));
903903
digest.update(methodName.getBytes(UTF_8));
904904
parameters.stream()
905+
.filter(parameter -> !Boolean.TRUE.equals(parameter.getExcluded()))
905906
.sorted(comparing(Parameter::getName).thenComparing(Parameter::getValue))
906907
.forEachOrdered(parameter -> {
907908
digest.update(parameter.getName().getBytes(UTF_8));
@@ -1009,17 +1010,25 @@ private List<Parameter> getParameters(final ITestContext context,
10091010
.forEach((name, value) -> result.put(name, createParameter(name, value)));
10101011
final Object instance = method.getInstance();
10111012
if (nonNull(instance)) {
1012-
Stream.of(instance.getClass().getDeclaredFields())
1013+
getClassHierarchy(instance.getClass()).stream()
1014+
.flatMap(type -> Stream.of(type.getDeclaredFields()))
10131015
.filter(field -> field.isAnnotationPresent(TestInstanceParameter.class))
10141016
.forEach(field -> {
1015-
final String name = Optional.ofNullable(field.getAnnotation(TestInstanceParameter.class))
1016-
.map(TestInstanceParameter::value)
1017+
final TestInstanceParameter annotation = field.getAnnotation(TestInstanceParameter.class);
1018+
final String name = Optional.of(annotation.value())
10171019
.filter(s -> !s.isEmpty())
10181020
.orElseGet(field::getName);
10191021
try {
10201022
field.setAccessible(true);
10211023
final String value = ObjectUtils.toString(field.get(instance));
1022-
result.put(name, createParameter(name, value));
1024+
result.put(
1025+
name, createParameter(
1026+
name,
1027+
value,
1028+
annotation.excluded(),
1029+
annotation.mode()
1030+
)
1031+
);
10231032
} catch (IllegalAccessException e) {
10241033
LOGGER.debug("Could not access field value");
10251034
}
@@ -1068,6 +1077,17 @@ private List<Parameter> getParameters(final ITestContext context,
10681077
.collect(Collectors.toList());
10691078
}
10701079

1080+
private static List<Class<?>> getClassHierarchy(final Class<?> type) {
1081+
final List<Class<?>> hierarchy = new ArrayList<>();
1082+
Class<?> current = type;
1083+
while (nonNull(current) && !Object.class.equals(current)) {
1084+
hierarchy.add(current);
1085+
current = current.getSuperclass();
1086+
}
1087+
Collections.reverse(hierarchy);
1088+
return hierarchy;
1089+
}
1090+
10711091
private String getMethodName(final ITestNGMethod method) {
10721092
return firstNonEmpty(
10731093
method.getDescription(),

allure-testng/src/main/java/io/qameta/allure/testng/TestInstanceParameter.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package io.qameta.allure.testng;
1717

18+
import io.qameta.allure.model.Parameter;
19+
1820
import java.lang.annotation.Documented;
1921
import java.lang.annotation.ElementType;
2022
import java.lang.annotation.Retention;
@@ -23,15 +25,38 @@
2325

2426
/**
2527
* You can use this annotation to add test instance parameters to your TestNG tests.
28+
* Fields declared by the test class and its superclasses are supported.
29+
* If multiple fields resolve to the same parameter name, the field declared by
30+
* the most-derived class takes precedence.
31+
*
32+
* @see Parameter
33+
* @see Parameter.Mode
2634
*/
2735
@Documented
2836
@Retention(RetentionPolicy.RUNTIME)
2937
@Target({ElementType.FIELD})
3038
public @interface TestInstanceParameter {
3139

3240
/**
33-
* The name of parameter.
41+
* The name of parameter. If empty, the field name will be used.
42+
*
43+
* @return the name of parameter.
3444
*/
3545
String value() default "";
3646

47+
/**
48+
* The parameter mode. It controls how the value is displayed and does not
49+
* exclude the parameter from history ID generation.
50+
*
51+
* @return the parameter mode.
52+
*/
53+
Parameter.Mode mode() default Parameter.Mode.DEFAULT;
54+
55+
/**
56+
* Set it to true to exclude the parameter from history ID generation.
57+
*
58+
* @return true if parameter is excluded, false otherwise.
59+
*/
60+
boolean excluded() default false;
61+
3762
}

allure-testng/src/test/java/io/qameta/allure/testng/AllureTestNgTest.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,6 +1639,70 @@ public void shouldSupportFactoryOnConstructor() {
16391639
);
16401640
}
16411641

1642+
@SuppressWarnings("unchecked")
1643+
@AllureFeatures.Parameters
1644+
@Test
1645+
public void shouldSupportInheritedTestInstanceParameterMetadata() {
1646+
final AllureResults results = runTestNgSuites("suites/test-instance-parameters.xml");
1647+
1648+
assertThat(results.getTestResults()).hasSize(3);
1649+
assertThat(results.getTestResults())
1650+
.allSatisfy(
1651+
testResult -> assertThat(testResult.getParameters())
1652+
.hasSize(3)
1653+
.extracting(
1654+
Parameter::getName,
1655+
Parameter::getValue,
1656+
Parameter::getExcluded,
1657+
Parameter::getMode
1658+
)
1659+
.contains(
1660+
tuple("overridden", "child-value", false, Parameter.Mode.DEFAULT)
1661+
)
1662+
);
1663+
assertThat(results.getTestResults())
1664+
.flatExtracting(TestResult::getParameters)
1665+
.filteredOn(parameter -> "iteration".equals(parameter.getName()))
1666+
.extracting(Parameter::getValue, Parameter::getExcluded, Parameter::getMode)
1667+
.containsExactlyInAnyOrder(
1668+
tuple("first", true, Parameter.Mode.DEFAULT),
1669+
tuple("second", true, Parameter.Mode.DEFAULT),
1670+
tuple("third", true, Parameter.Mode.DEFAULT)
1671+
);
1672+
assertThat(results.getTestResults())
1673+
.flatExtracting(TestResult::getParameters)
1674+
.filteredOn(parameter -> "hidden".equals(parameter.getName()))
1675+
.extracting(Parameter::getValue, Parameter::getExcluded, Parameter::getMode)
1676+
.containsExactlyInAnyOrder(
1677+
tuple("hidden-value", false, Parameter.Mode.HIDDEN),
1678+
tuple("hidden-value", false, Parameter.Mode.HIDDEN),
1679+
tuple("different-hidden-value", false, Parameter.Mode.HIDDEN)
1680+
);
1681+
}
1682+
1683+
@AllureFeatures.Parameters
1684+
@AllureFeatures.History
1685+
@Test
1686+
public void shouldExcludeTestInstanceParameterFromHistoryId() {
1687+
final AllureResults results = runTestNgSuites("suites/test-instance-parameters.xml");
1688+
1689+
assertThat(results.getTestResults()).hasSize(3);
1690+
final Map<String, String> historyIds = results.getTestResults().stream()
1691+
.collect(
1692+
Collectors.toMap(
1693+
testResult -> testResult.getParameters().stream()
1694+
.filter(parameter -> "iteration".equals(parameter.getName()))
1695+
.map(Parameter::getValue)
1696+
.findFirst()
1697+
.orElseThrow(),
1698+
TestResult::getHistoryId
1699+
)
1700+
);
1701+
assertThat(historyIds.values()).doesNotContainNull();
1702+
assertThat(historyIds.get("first")).isEqualTo(historyIds.get("second"));
1703+
assertThat(historyIds.get("first")).isNotEqualTo(historyIds.get("third"));
1704+
}
1705+
16421706
@SuppressWarnings("unchecked")
16431707
@AllureFeatures.Parameters
16441708
@Issue("893")
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2016-2026 Qameta Software Inc
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.testng.samples;
17+
18+
import io.qameta.allure.model.Parameter;
19+
import io.qameta.allure.testng.TestInstanceParameter;
20+
21+
public abstract class TestInstanceParameterBase {
22+
23+
@TestInstanceParameter(
24+
value = "iteration",
25+
excluded = true
26+
)
27+
private final String iteration;
28+
29+
@TestInstanceParameter(
30+
value = "hidden",
31+
mode = Parameter.Mode.HIDDEN
32+
)
33+
private final String hidden;
34+
35+
@TestInstanceParameter("overridden")
36+
private final String overridden = "base-value";
37+
38+
protected TestInstanceParameterBase(final String iteration, final String hidden) {
39+
this.iteration = iteration;
40+
this.hidden = hidden;
41+
}
42+
43+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2016-2026 Qameta Software Inc
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.testng.samples;
17+
18+
import io.qameta.allure.testng.TestInstanceParameter;
19+
import org.testng.annotations.DataProvider;
20+
import org.testng.annotations.Factory;
21+
import org.testng.annotations.Test;
22+
23+
public class TestInstanceParameterInheritanceTests extends TestInstanceParameterBase {
24+
25+
@TestInstanceParameter("overridden")
26+
private final String overridden = "child-value";
27+
28+
@Factory(dataProvider = "instances")
29+
public TestInstanceParameterInheritanceTests(final String iteration, final String hidden) {
30+
super(iteration, hidden);
31+
}
32+
33+
@DataProvider
34+
public static Object[][] instances() {
35+
return new Object[][]{
36+
new Object[]{"first", "hidden-value"},
37+
new Object[]{"second", "hidden-value"},
38+
new Object[]{"third", "different-hidden-value"},
39+
};
40+
}
41+
42+
@Test
43+
public void factoryTest() {
44+
}
45+
46+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
3+
4+
<suite name="Test instance parameters">
5+
<test name="test-instance-parameters">
6+
<classes>
7+
<class name="io.qameta.allure.testng.samples.TestInstanceParameterInheritanceTests"/>
8+
</classes>
9+
</test>
10+
</suite>

0 commit comments

Comments
 (0)