Уникальная идентификация каждого вызова теста в testng

Хорошо, поэтому у меня есть класс, подобный этому

public class Calculator {

    @Test(dataProvider = "dp")
    public void add(int a, int b) {
        System.out.println("Invoked add: a, b" + a + "," + b);
    }

    @DataProvider(name = "dp")
    public Object[][] createData(ITestContext ctx) {
        return new Object[][] { new Object[] { 1, 2 }, new Object[] { 2, 3 } };
    }

Когда при запуске теста он будет запускать метод добавления дважды. Я хочу отслеживать каждый вызов, добавляемый уникально на основе его ввода. Так сказать, add вызывается с 1,2 в качестве ввода, а затем уникальным вызовом. Если это не удается, я хочу сохранить эту информацию в базе данных с идентификатором вызова.

Как достичь этого с помощью testng? Все слушатели (methodinvocationlistener и т.д.), Похоже, не предоставляют контекст, который однозначно идентифицирует прогон метода. Да, они позволяют вам видеть параметры, но я не могу отслеживать отдельные параметры. Итак, каким-то образом я ввожу свой собственный уникальный параметр в объект результата и отслеживаю его там?

UPDATE

Я добавляю улучшенный код, чтобы лучше понять контекст. Это мой testng.xml

<suite name="Default Suite">
  <test name="test">
    <classes>
      <class name="com.test.testng.Calculator">
        <methods>
          <include name="add">
            <parameter name="data-id" value="1"/>
          </include> <!-- add -->
          <include name="add">
            <parameter name="data-id" value="2"/>
          </include> <!-- add -->
          <include name="subtract">
            <parameter name="data-id" value="3"/>
          </include> <!-- subtract -->
        </methods>
      </class> <!-- com.test.testng.Calculator -->
    </classes>
  </test> <!-- test -->
</suite> <!-- Default Suite -->

У меня есть два вызова add и один вызов вычитания. Здесь мой поставщик данных

public class Calculator {

    @Test(dataProvider = "dp")
    public void add(int first, int second) {
        System.out.println("invoked add");
    }

    @Test(dataProvider = "dp")
    public void subtract(int first, int second) {
        System.out.println("invoked subtract");
    }

    @DataProvider(name = "dp")
    public Object[][] createData(Method m, ITestContext ctx) {    
        Object[][] data = new Object[][] { new Object[] { 1, 2 }, new Object[] { 2, 3 }, new Object[] { 3, 4 } };
        for (XmlClass test : ctx.getCurrentXmlTest().getXmlClasses()) {
            for (XmlInclude method : test.getIncludedMethods()) {
                if (method.getName().equals(m.getName()))
                int key = Integer.parseInt(method.getAllParameters().get("data-id"));
                return new Object[][] { data[key - 1] };
            }
        }
        return null ;
    }

}

Я ожидал, добавьте для запуска дважды, один раз с 1,2 в качестве входных данных, а другой раз с 2,3 в качестве ввода. Аналогично, вычитайте с 3,4 в качестве входных данных. Но, что я увидел, это -

[SuiteRunner] Created 1 TestRunners
[TestRunner] Running test test on 1  classes,  included groups:[] excluded groups:[]
===== Test class
com.test.testng.Calculator
    @Test Calculator.add(int, int)[pri:0, instance:[email protected]]
    @Test Calculator.subtract(int, int)[pri:0, instance:[email protected]]
======
method.getAllParamas(){data-id=1}

[Invoker 665576141] Invoking com.test.testng.Calculator.add
invoked

[Invoker 665576141] Invoking com.test.testng.Calculator.subtract
subtract
===== Invoked methods
    Calculator.add(int, int)[pri:0, instance:[email protected]]1 2  966808741
    Calculator.subtract(int, int)[pri:0, instance:[email protected]]1 2  966808741
=====

Мне нужно предоставить данные для каждого метода на основе специального параметра, который я собираюсь отправить из testng xml. Как достичь этого?

Ответ 1

Для этого вы можете определить различные тесты в testng.xml, например:

<suite name="Default Suite">
  <test name="test">
    <classes>
      <class name="com.test.testng.Calculator">
        <methods>
          <include name="add">
            <parameter name="data-id" value="1"/>
          </include> <!-- add -->
          <include name="subtract">
            <parameter name="data-id" value="3"/>
          </include> <!-- subtract -->
        </methods>
      </class> <!-- com.test.testng.Calculator -->
    </classes>
  </test> <!-- test -->
  <test name="test2">
    <classes>
      <class name="com.test.testng.Calculator">
        <methods>
          <include name="add">
            <parameter name="data-id" value="2"/>
          </include> <!-- add -->
        </methods>
      </class> <!-- com.test.testng.Calculator -->
    </classes>
  </test> <!-- test -->
</suite> <!-- Default Suite -->

Я добавляю метод поставщика журнала:

package com.test.testng;

import java.lang.reflect.Method;

import org.testng.ITestContext;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlInclude;

public class Calculator {

    @Test(dataProvider = "dp")
    public void add(int first, int second) {
        System.out.println("invoked add");
    }

    @Test(dataProvider = "dp")
    public void subtract(int first, int second) {
        System.out.println("invoked subtract");
    }

    @DataProvider(name = "dp")
    public Object[][] createData(Method m, ITestContext ctx) {    
        Object[][] data = new Object[][] { new Object[] { 1, 2 }, new Object[] { 2, 3 }, new Object[] { 3, 4 } };
        for (XmlClass test : ctx.getCurrentXmlTest().getXmlClasses()) {
            for (XmlInclude method : test.getIncludedMethods()) {

                if (method.getName().equals(m.getName())) {
                    int key = Integer.parseInt(method.getAllParameters().get("data-id"));
                    System.out.println("Running method " + m.getName() + "  with data-id: " + key);
                    return new Object[][] { data[key - 1] };
                }


            }
        }
        return null ;
    }

}

Запуск этого xml в качестве пакета testng (с плагином eclipse) показывает следующее:

[TestNG] Running:
  /Users/fhernandez/Documents/workspaceTest/testNg-test/src/test/resources/testng.xml

Running method add  with data-id: 1
invoked add
Running method subtract  with data-id: 3
invoked subtract
Running method add  with data-id: 2
invoked add

===============================================
Default Suite
Total tests run: 3, Failures: 0, Skips: 0
===============================================

Если я хорошо понимаю ваши требования, с этим вы можете достичь этого.

Другим способом достижения этого может быть поставлен аспект или прокси-сервер перед тестовыми классами и провести проверку вызова метода, реализуя в этом аспекте/прокси ваши требования.

UPDATE

Я добавляю Listener в калькулятор с

@Listeners(Listener.class)
public class Calculator

Слушатель выглядит следующим образом

    package com.test.testng;

import java.util.Arrays;

import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.ITestResult;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlInclude;

public class Listener implements IInvokedMethodListener {

    public void afterInvocation(IInvokedMethod method, ITestResult itr) {
        // TODO implements
    }

    public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {

        // Parameters value
        System.out.println("Parameters invocation value for method " + method.getTestMethod().getMethodName());
        Arrays.asList(testResult.getParameters()).stream().forEach(System.out::println);

        // get data-id
        for (XmlClass test : testResult.getTestContext().getCurrentXmlTest().getXmlClasses()) {
            for (XmlInclude met : test.getIncludedMethods()) {

                if (met.getName().equals(method.getTestMethod().getMethodName())) {
                    int key = Integer.parseInt(met.getAllParameters().get("data-id"));
                    System.out.println("listener: Running method " + method.getTestMethod().getMethodName() + "  with data-id: " + key);
                }        
            }
        }
    }
}

В коде beforeInvocation отображаются значения вызова параметра и идентификатор данных, это вывод

    [TestNG] Running:
  /Users/fhernandez/Documents/workspaceTest/testNg-test/src/test/resources/testng.xml

Running method add  with data-id: 1
Parameters invocation value for method add
1
2
listener: Running method add  with data-id: 1
invoked add
Running method subtract  with data-id: 3
Parameters invocation value for method subtract
3
4
listener: Running method subtract  with data-id: 3
invoked subtract
Running method add  with data-id: 2
Parameters invocation value for method add
2
3
listener: Running method add  with data-id: 2
invoked add

===============================================
Default Suite
Total tests run: 3, Failures: 0, Skips: 0
===============================================

Ответ 2

Первый аргумент в [] [] - это число тестовых прогонов. Во-вторых, количество параметров. Т.е.
  public Object [] [] createData (ITestContext ctx) {       return new Object [] [] {new Object [] {0,2}, новый объект [] {0,3}       };   }


Пройдет один тест с двумя параметрами 2,3.

Ответ 3

Модульные тесты предназначены для разработчика, чтобы проверить свой собственный код, и никто другой.

Комментарии к вопросу указывают, что "пользовательские параметры/тесты" находятся в контексте, который помещает его в область тестирования системы.

Не используйте модульную систему тестирования для выполнения системных тестов.

Важным моментом является то, что в предлагаемой среде возможно что-то внешнее по отношению к коду (пользователю, добавляющему новые параметры теста), чтобы сломать сборку. Это плохо. Очень плохо. Если требуется новая функциональность, разработчик улучшит код и добавит новые тесты, чтобы покрыть его.

Посмотрите на BDD рамки JBehave, который, по-видимому, лучше подходит вам.