Override TestNG Test name when using a provider an

2019-07-27 01:26发布

Have the following Sample code ... when running tests (and in reports), I would like the Test Names to be set to the description field provided by the provider (really it's any String).

... however, even when extending from ITest, it seems like all the provider parameters get appended to the TestName, what I want is the description only.

So actual test name should be "TestName1" instead of "TestName2[1](TestName2, 2, 2, 4)" .. which is what is showing up in XML reports, and test.aftertest name.

import org.testng.Assert;
import org.testng.ITest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.lang.reflect.Method;

public class TestNgProviderExample implements ITest{

    @Test(dataProvider = "summationProvider")
    public void testProvider(String description, int number1, int number2, int sum) {
        Assert.assertEquals(sum, number1 + number2);
    }

    @DataProvider(name = "summationProvider")
    public Object[][] summationData() {
        Object[][] testData = {{"TestName1",1,2,3},{"TestName2",2,2,4}};
        return testData;
    }

    private String reportedTestName = "";

    @BeforeMethod(alwaysRun = true)
    public void testData(Method method, Object[] testData) {
        reportedTestName = testData[0].toString();
    }

    @Override
    public String getTestName() {
        return reportedTestName;
    }
}

1条回答
The star\"
2楼-- · 2019-07-27 02:18

Simply running a @Test-annotated method without parameters can solve it.
Instead of parameters my solution uses class fields and a constructor @Factory method.

public class TestClass implements ITest {

    protected String description;
    protected int firstNumber;
    protected int secondNumber;
    protected int sum;

    @Test
    public void testProvider() {
        /**
         * Minus or plus here to make it fail or pass.
         */
        assertEquals(this.sum, this.firstNumber - this.secondNumber);
    }

    @Factory(dataProvider = "summationProvider")
    public TestClass(String description,
                     int firstNumber, int secondNumber, int sum) {
        this.description = description;
        this.firstNumber = firstNumber;
        this.secondNumber = secondNumber;
        this.sum = sum;
    }

    @DataProvider(name = "summationProvider")
    public static Object[][] summationData() {
        Object[][] testData = {{"TestName1", 1, 2, 3}, {"TestName2", 2, 2, 4}};
        return testData;
    }

    @Override
    public String getTestName() {
        return this.description;
    }
}

Output with formatting from my IntelliJ Idea: enter image description here

Of course, it is possible to make the @Factory instantiate another class, not the same TestClass.

And if you have 40 separate variables from parameters and want to keep it short... Add a class that would be a holder for those parameters, e.g. ParametrizedInput. It would at least make it possible to hide all those instance variables. You can place description in the second class as well (in that case ThreadLocal<ParametrizedInput> usage would be advised).
The second class will grow with parameters, but since it is a plain old Java object, it shouldn't break anything in test. If you don't want to set all those variables, another idea would be to access parameters lazily in tests. Following expert's (Krishnan Mahadevan) advice I figured out that the name with a method can be set with a @BeforeMethod- and @AfterMethod-annotated methods.

public class TestClass implements ITest {

    protected static ThreadLocal<String> description
            = new ThreadLocal<>();
    protected ParametrizedInput input;

    @BeforeMethod
    public void setUp(Method method) {
        this.description.set(this.description.get() + " " + method.getName());
    }

    @AfterMethod
    public void tearDown(Method method) {
        this.description.set(this.description.get().substring(0,
                this.description.get().length() - method.getName().length()));
    }

    @Test
    public void testProvider() {
        assertEquals(this.input.getSum(),
                this.input.getFirstNumber() / this.input.getSecondNumber());
    }

    @Test
    public void anotherTestProvider() {
        assertEquals(this.input.getSum(),
                this.input.getFirstNumber() - this.input.getSecondNumber());
    }
    @Factory(dataProvider = "summationProvider")
    public TestClass(String descriptionString, ParametrizedInput input) {
        this.description.set(descriptionString);
        this.input = input;
    }

    @DataProvider(name = "summationProvider")
    public static Object[][] summationData() {
        Object[][] testData = {{"TestName1", new ParametrizedInput(1, 2, 3)},
                {"TestName2", new ParametrizedInput(2, 2, 4)}};
        return testData;
    }

    @Override
    public String getTestName() {
        return this.description.get();
    }
}

Parameter Holder class:

public class ParametrizedInput {

    private int firstNumber;
    private int secondNumber;
    private int sum;

    public ParametrizedInput(int firstNumber,
                             int secondNumber, int sum) {
        this.firstNumber = firstNumber;
        this.secondNumber = secondNumber;
        this.sum = sum;
    }

    public int getFirstNumber() {
        return firstNumber;
    }

    public int getSecondNumber() {
        return secondNumber;
    }

    public int getSum() {
        return sum;
    }
}

Result:
enter image description here

查看更多
登录 后发表回答