Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TestNG using multiple DataProviders with single Test method

I have been looking for a way to use multiple DataProviders in my test method. My scenario is as follows:

lets say we have a DataProvider class:

@Test
public class ExampleDataProvider {

   /**
     * Returns the list of shape codes.
     * 
     * @return the collection shape codes.
     */
    @DataProvider(name = "ShapeCodes")
    public static Object[][] getShapeCodes() {
        return new Object[][] { new Object[] { Shape.Square }, 
            new Object[] { Shape.Triangle }
        };
    }

    /**
     * Returns the list of color codes.
     * 
     * @return the collection of color codes.
     */
    @DataProvider(name = "ColorCodes")
    public static Object[][] geColorCodes() {
        return new Object[][] { new Object[] { Color.Green }, 
            new Object[] { Color.Red }
        };
    }
}

Now in my Test method I want to run for all combinations of scenarios:

  1. Green-Square
  2. Red-Square
  3. Green-Triangle
  4. Red-triangle

How should I achieve this in my code, given that I cant specify multiple DataProviders with @Test annotation

@Test(dataProvider = "ShapeCodes", dataProviderClass = ExampleDataProvider.class)
    public void test(String ShapeCode, String ColorCode) throws IOException {
        .............
        /* tests for color shape combination */
        .............
    }

EDIT : I found a similar problem and a @ workaround but I am still wondering if there are better ways to handle this.

like image 481
Segmented Avatar asked Aug 28 '14 12:08

Segmented


People also ask

Can we use multiple DataProvider in TestNG?

However, TestNG parameters enable us to pass the values only once per execution cycle. To overcome this, we can use DataProvider in TestNG that allows us to pass multiple parameters to a single test in a single execution. Using DataProviders, we can easily pass multiple values to a test in just one execution cycle.

How do you run a test case with multiple data in TestNG?

We can run multiple test cases using TestNG test suite in Selenium webdriver. To execute test cases simultaneously, we have to enable parallel execution in TestNG. A TestNG execution is driven by the TestNG xml file. To trigger parallel execution we have to use the attributes – parallel and thread-count.

What is the difference between DataProvider and parameters in TestNG?

What is the difference between DataProvider and Parameter in TestNG? DataProviders pass the different parameters on a single test in a single execution, whereas parameters pass the parameters just once per execution in TestNG.

What is DataProvider annotation in TestNG?

The Complete TestNG & Automation Framework Design Course @DataProvider annotation helps us write data-driven test cases. The @DataProvider annotation enables us to run a test method multiple times by passing different data-sets.


3 Answers

For the lack of a better approach, I decided to stick to the workaround. here is an example of how the above scenario could be implemented:

@Test
public class ExampleDataProvider {

   /**
     * Returns the list of shape codes.
     * 
     * @return the collection shape codes.
     */
    @DataProvider(name = "ShapeCodes")
    public static Object[][] getShapeCodes() {
        return new Object[][] { new Object[] { Shape.Square }, 
            new Object[] { Shape.Triangle }
        };
    }

    /**
     * Returns the list of color codes.
     * 
     * @return the collection of color codes.
     */
    @DataProvider(name = "ColorCodes")
    public static Object[][] geColorCodes() {
        return new Object[][] { new Object[] { Color.Green }, 
            new Object[] { Color.Red }
        };
    }

    /**
     * Returns the list object codes providing a color shape combination.
     * 
     * @return the collection of object codes.
     */
    @DataProvider(name = "objectCodes")
    public static Object[][] getObjectCodes(){
        return combine(geColorCodes(),  getShapeCodes());
    }


    /**
     * Returns the list of combination of color and shape codes.
     * 
     * @return the collection of combined color and shape codes.
     */
    public static Object[][] combine(Object[][] a1, Object[][] a2){
        List<Object[]> objectCodesList = new LinkedList<Object[]>();
        for(Object[] o : a1){
            for(Object[] o2 : a2){
                objectCodesList.add(concatAll(o, o2));
            }
        }
         return objectCodesList.toArray(new Object[0][0]);
    }


    @SafeVarargs
    public static <T> T[] concatAll(T[] first, T[]... rest) {
     //calculate the total length of the final object array after the concat    
      int totalLength = first.length;
      for (T[] array : rest) {
        totalLength += array.length;
      }
      //copy the first array to result array and then copy each array completely to result
      T[] result = Arrays.copyOf(first, totalLength);
      int offset = first.length;
      for (T[] array : rest) {
        System.arraycopy(array, 0, result, offset, array.length);
        offset += array.length;
      }

      return result;
    }
}

This way I get to use my Color codes and Shape codes separately and also provides me to use the combination.

So, my test methods would look like:

@Test(dataProvider = "objectCodes", dataProviderClass = ExampleDataProvider.class)
     public void test(String ShapeCode, String ColorCode) throws IOException {
           .............
           /* tests for color shape combination */
           .............
          }

@Test(dataProvider = "ShapeCodes", dataProviderClass = ExampleDataProvider.class)
    public void test(String ShapeCode) throws IOException {
        .............
        /* tests for  shapes */
        .............
    }

@Test(dataProvider = "ColorCodes", dataProviderClass = ExampleDataProvider.class)
    public void test(String ColorCode) throws IOException {
        .............
        /* tests for colors */
        .............
    }
like image 132
Segmented Avatar answered Oct 07 '22 01:10

Segmented


Great answer Segmented

Maybe someone will need it too, I rewrote this method in a different way.

// public static <T> T[] concatAll(T[] first, T[]... rest) {

public static Object[] concat(Object[] first, Object[] second) {
        Object[] result = ArrayUtils.addAll(first, second);
        return result;
like image 20
Sashko Avatar answered Oct 07 '22 02:10

Sashko


https://stackoverflow.com/a/59993761/5016494

This may help

    @DataProvider
    public Object[][] combinedDataProvider() {
        return Stream.of(dp1(), dp2())
                .flatMap(Arrays::stream)
                .toArray(Object[][]::new);
    }
like image 37
Wee Avatar answered Oct 07 '22 02:10

Wee