What happened?
Describe the bug
TestNG resolves suite XML parameters with the most-specific scope winning: a <class>-level <parameter> overrides the <test>-level one, which overrides the <suite>-level one. Values injected via @Parameters (e.g. into @BeforeMethod/@Test methods) respect this correctly.
However, allure-testng attaches XML parameters to every test result using only the <test>-level map:
https://github.com/allure-framework/allure-java/blob/master/allure-testng/src/main/java/io/qameta/allure/testng/AllureTestNg.java#L1041-L1046
context.getCurrentXmlTest().getAllParameters()
.forEach((name, value) -> result.put(name, createParameter(name, value)));
XmlTest#getAllParameters() merges suite + test parameters but knows nothing about XmlClass local parameters. As a result, for any test method that does not inject the parameter itself, the Allure report shows the <test>-level value even when the class overrides it — i.e. the report claims a configuration the test did not actually run with.
Real-world impact: our @BeforeMethod browser fixture consumes a headless parameter. One class overrides it to false at <class> level (and the browser really starts headed — verified), but every test of that class is reported in Allure / Allure TestOps with headless: true.
Steps to reproduce
testng.xml:
<suite name="Repro" parallel="methods" thread-count="2">
<test name="Repro">
<parameter name="headless" value="true"/>
<classes>
<class name="example.NoOverrideTest"/>
<class name="example.OverrideTest">
<parameter name="headless" value="false"/>
</class>
</classes>
</test>
</suite>
NoOverrideTest.java:
package example;
import org.testng.annotations.Optional;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
public class NoOverrideTest {
@Parameters("headless")
@Test
public void injectingTest(@Optional("missing") String headless) {
System.out.println(headless); // prints "true"
}
}
OverrideTest.java:
package example;
import org.testng.annotations.Optional;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
public class OverrideTest {
@Parameters("headless")
@Test
public void injectingTest(@Optional("missing") String headless) {
System.out.println(headless); // prints "false" — TestNG applies the class-level override
}
@Test
public void plainTest() {
// does not inject the parameter itself
}
}
Run the suite and inspect allure-results/*-result.json:
| Test |
Actual effective value |
parameters in result.json |
NoOverrideTest.injectingTest |
true |
headless: true ✅ |
OverrideTest.injectingTest |
false |
headless: false ✅ (method argument wins over the XML map) |
OverrideTest.plainTest |
false (class-level override) |
headless: true ❌ |
Expected behavior
OverrideTest.plainTest should be reported with headless: false. XML parameters attached to a test result should be resolved the same way TestNG resolves them, i.e. XmlClass local parameters should be merged over XmlTest parameters, for example:
context.getCurrentXmlTest().getAllParameters()
.forEach((name, value) -> result.put(name, createParameter(name, value)));
final XmlClass xmlClass = method.getTestClass().getXmlClass();
if (Objects.nonNull(xmlClass)) {
xmlClass.getLocalParameters()
.forEach((name, value) -> result.put(name, createParameter(name, value)));
}
Versions
| Component |
Version |
| allure-testng |
2.35.4 |
| TestNG |
7.12.0 |
| JDK |
21 |
| OS |
macOS (Darwin 25.5) |
Originally observed in a Kotlin test project; reproduced identically with plain Java classes.
What Allure Integration are you using?
allure-testng
What version of Allure Integration you are using?
2.35.4
What version of Allure Report you are using?
2.35.1
Code of Conduct
What happened?
Describe the bug
TestNG resolves suite XML parameters with the most-specific scope winning: a
<class>-level<parameter>overrides the<test>-level one, which overrides the<suite>-level one. Values injected via@Parameters(e.g. into@BeforeMethod/@Testmethods) respect this correctly.However,
allure-testngattaches XML parameters to every test result using only the<test>-level map:https://github.com/allure-framework/allure-java/blob/master/allure-testng/src/main/java/io/qameta/allure/testng/AllureTestNg.java#L1041-L1046
XmlTest#getAllParameters()merges suite + test parameters but knows nothing aboutXmlClasslocal parameters. As a result, for any test method that does not inject the parameter itself, the Allure report shows the<test>-level value even when the class overrides it — i.e. the report claims a configuration the test did not actually run with.Real-world impact: our
@BeforeMethodbrowser fixture consumes aheadlessparameter. One class overrides it tofalseat<class>level (and the browser really starts headed — verified), but every test of that class is reported in Allure / Allure TestOps withheadless: true.Steps to reproduce
testng.xml:NoOverrideTest.java:OverrideTest.java:Run the suite and inspect
allure-results/*-result.json:parametersin result.jsonNoOverrideTest.injectingTesttrueheadless: true✅OverrideTest.injectingTestfalseheadless: false✅ (method argument wins over the XML map)OverrideTest.plainTestfalse(class-level override)headless: true❌Expected behavior
OverrideTest.plainTestshould be reported withheadless: false. XML parameters attached to a test result should be resolved the same way TestNG resolves them, i.e.XmlClasslocal parameters should be merged overXmlTestparameters, for example:Versions
Originally observed in a Kotlin test project; reproduced identically with plain Java classes.
What Allure Integration are you using?
allure-testng
What version of Allure Integration you are using?
2.35.4
What version of Allure Report you are using?
2.35.1
Code of Conduct