Repository navigation
Description
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:
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
- I agree to follow this project's Code of Conduct
Activity
respect testng xml parameter overrides in reported results (fixes all…