Переопределить имя теста TestNG при использовании поставщика и опустить параметры

Имейте следующий пример кода... при запуске тестов (и в отчетах) я бы хотел, чтобы имена тестов были установлены в поле описания, предоставленное поставщиком (на самом деле это любая строка).

... однако, даже при расширении от ITest кажется, что все параметры провайдера добавляются к TestName, я хочу только описание.

Таким образом, фактическое имя теста должно быть "TestName1" вместо "TestName2[1](TestName2, 2, 2, 4)" .. это то, что отображается в отчетах XML, и имя test.aftertest.

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;
    }
}

person vicsz    schedule 10.03.2017    source источник
comment
Я создал задачу о проблеме: github.com/cbeust/testng/issues/1382   -  person juherr    schedule 11.03.2017


Ответы (1)


Простой запуск @Test-аннотированного метода без параметров может решить эту проблему.
Вместо параметров в моем решении используются поля класса и метод конструктора @Factory.

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;
    }
}

Вывод с форматированием из моей идеи IntelliJ: введите здесь описание изображения

Конечно, можно заставить @Factory создавать экземпляр другого класса, а не того же TestClass.

И если у вас есть 40 отдельных переменных из параметров и вы хотите, чтобы они были короткими... Добавьте класс, который будет держателем этих параметров, например. ParametrizedInput. По крайней мере, это позволило бы скрыть все эти переменные экземпляра. Вы также можете поместить description во второй класс (в этом случае рекомендуется использовать ThreadLocal<ParametrizedInput>).
Второй класс будет увеличиваться с параметрами, но, поскольку это старый простой объект Java, он не должен ничего ломать в тесте. . Если вы не хотите устанавливать все эти переменные, другой идеей будет ленивый доступ к параметрам в тестах. Следуя совету эксперта (Кришнан Махадеван), я понял, что имя с методом можно установить с помощью @BeforeMethod- и @AfterMethod-аннотированные методы.

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();
    }
}

Класс владельца параметра:

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;
    }
}

Результат:
введите здесь описание изображения

person Grzegorz Górkiewicz    schedule 10.03.2017
comment
Спасибо! .. есть ли способ сделать это без Factory? это может быть сложно с кодовой базой, с которой я имею дело. - person vicsz; 11.03.2017
comment
Почему это может стать трудным? Если в одном классе слишком много поставщиков данных или тестов, просто разделите его. Я использую фабрики и у меня не так много проблем с ними ;) - person Grzegorz Górkiewicz; 11.03.2017
comment
Унаследованная кодовая база .. Что-то вроде 40 параметров, предпочел бы не определять добавление 40 переменных экземпляра ... но похоже, что ваше решение - единственный способ, и нет никакого способа обойти это ... Если я что-то упустил? - person vicsz; 11.03.2017
comment
@GrzegorzGórkiewicz - Реализация, которой вы поделились, лучше всего подходит для тестовых классов, в которых есть ровно один метод @Test. Когда вы добавляете еще @Test методов в один и тот же тестовый класс, он снова сталкивается с той же проблемой. - person Krishnan Mahadevan; 11.03.2017
comment
@KrishnanMahadevan, не совсем понимаю, но обычно ты прав. Если я обращаюсь к переменным экземпляра класса с помощью геттеров, параметров нет, и проблем нет. - person Grzegorz Górkiewicz; 11.03.2017
comment
@GrzegorzGórkiewicz. Может быть, этот мой пост в блоге разъяснит, о чем я говорю rationaleemotions.wordpress.com/2013/07/31/ В двух словах, когда у вас есть 2 или более @Test методов, тогда TestNG использует одну и ту же реализацию ITest для отображения их имен. - person Krishnan Mahadevan; 11.03.2017
comment
@KrishnanMahadevan, спасибо. Я обновил свой ответ, чтобы можно было обрабатывать многие методы @Test. - person Grzegorz Górkiewicz; 11.03.2017
comment
@KrishnanMahadevan, ОП хотел скрыть все параметры из отчетов. Чтобы не скрывать имена методов, я добавил @BeforeMethod- и @AfterMethod-аннотированные методы, - person Grzegorz Górkiewicz; 11.03.2017
comment
@GrzegorzGórkiewicz - Вы пробовали запускать методы тестирования параллельно :) Думаю, результаты будут интересными. Вы можете сделать поле this.description переменной ThreadLocal, чтобы гарантировать, что мы позаботимся и об этом условии. - person Krishnan Mahadevan; 11.03.2017
comment
@KrishnanMahadevan, разве @*Method аннотированные методы не выполняются в том же потоке, что и методы тестирования? - person Grzegorz Górkiewicz; 11.03.2017
comment
да, они делают. Но если вы заметили, теперь все они в основном пытаются перезаписать один и тот же член данных класса одновременно. Таким образом, последний запущенный поток (в модели параллельного выполнения) обновит его до последнего доступного для чтения значения. - person Krishnan Mahadevan; 11.03.2017
comment
Давайте продолжим это обсуждение в чате. - person Grzegorz Górkiewicz; 11.03.2017
comment
Упростил мой ответ. - person Grzegorz Górkiewicz; 11.03.2017