0

I am trying to build a Selenium hybrid framework using TestNG wherein i am getting data from my excel datasheet. I am trying to use DataProvider of testNG, But problem is since my datasheet contains data which belongs to different test case (for eg. 2 rows for add user, 1 rows for modify user, some rows for searching user etc)

since my dataprovider will return all the data from datasheet and passing it to any particular testCase that will run for all row of dataprovider will cause problem (eg. create user will need 5 parameter but the data of edit user will not be sufficient to it).

how can we handle this problem?

JeffC
  • 22,180
  • 5
  • 32
  • 55
Ankit Singh
  • 77
  • 2
  • 7
  • 1
    "my datasheet contains data which belongs to different test case": Why? There should be a DataProvider for each test case. Why not having a separate sheet for each test case. So every sheet will be its own DataProvider? So each DataProvider has to know from which sheet it shall get it's data. Else each DataProider has to know from which range of the single sheet it shall get it's data. – Axel Richter May 06 '18 at 05:25
  • data provider limits your data scope to script level as @Dataprovider cannot are not as flexible as other annotation. So, to overcome this problem , I recommend to have a read function (that reads data from excel sheets) as the pre-requisite in every test class. This method call must be parameterised with @ Parameter annotation. – Manmohan_singh May 06 '18 at 05:39
  • @AxelRichter... so you want me to have each sheet for each testcase. what if number of test cases are 500, is it not bad design and difficult to manage 500 excel sheets. – Ankit Singh May 06 '18 at 05:56
  • @Manmohan_singh as part of my framework design i want to read excel data at once, i kind off want to avoid reading data from excel continuously for the performance sake. So i read what all test cases are marked "True" for running and i read those testcases's data from datasheet in once go and store in arraylist – Ankit Singh May 06 '18 at 06:01
  • As said, each DataProider has to know from where it shall get its data. Either from different sheets or from different ranges of one sheet. Your decision. A other way would be having one DataProvider having `java.lang.reflect.Method` as first parameter. Then this DataProvider will know from that parameter which method has called it. Then it could get the data dependent on this method. But will this really be of great performance? I don't think so. – Axel Richter May 06 '18 at 06:20

1 Answers1

1

Here's how you do this:

  • Within your .xls file, create a sheet which represents a particular functionality. (For e.g, login, compose, address-book etc., if I were to be taking the example of an emailing application)
  • Now each sheet would have test data for various test cases, that test out that particular functionality.
  • In your @Test method, you can create a new custom annotation (this would be a marker annotation), which would indicate the "sheet" name from which the data provider should be retrieving data from. If you are not keen on creating a new custom annotation, then you can make use of the "description" attribute of the @Test annotation to capture this information.
  • TestNG can natively inject a Method object to your @DataProvider annotated method. Here the Method object that was injected would represent the @Test method for which the data provider is about to be invoked. So now you can retrieve the sheet name, either from the new custom annotation (or) from the description attribute of the @Test annotation to figure out which sheet name to query for data.

That should solve your issue.

Here's a sample that demonstrates the overall idea. You would need to enrich the data provider, such that it uses the sheet name to query data from the excel spreadsheet. My sample just excludes all of that, for the sake of demonstration.

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.METHOD;

@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({METHOD})
public @interface SheetName {
    String value() default "";
}
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.lang.reflect.Method;

public class TestClass {

  @Test(dataProvider = "dp")
  @SheetName("one")
  public void test1(String name) {
    System.err.println("Name is " + name);
  }

  @Test(dataProvider = "dp")
  @SheetName("two")
  public void test2(int age) {
    System.err.println("Age is " + age);
  }

  @DataProvider(name = "dp")
  public Object[][] getData(Method method) {
    String sheetName = getSheetName(method);
    if (sheetName == null) {
      // Handle the case, wherein our custom annotation is missing. That means the test perhaps
      // expects
      // either all of the data, or it could be a error case.
      return new Object[][] {{}};
    }
    if ("one".equalsIgnoreCase(sheetName)) {
      return new Object[][] {{"Cedric"}, {"Beust"}};
    }
    if ("two".equalsIgnoreCase(sheetName)) {
      return new Object[][] {{1}, {2}};
    }
    // Handle the case, wherein we had a valid sheet name, but it represents a sheet that cant be
    // found in our
    // excel spreadsheet.
    return new Object[][] {{}};
  }

  private String getSheetName(Method method) {
    SheetName sheetName = method.getAnnotation(SheetName.class);
    if (sheetName == null || sheetName.value().trim().isEmpty()) {
      return null;
    }
    return sheetName.value();
  }
}
Krishnan Mahadevan
  • 14,121
  • 6
  • 34
  • 66