Reputation: 143
Reading testdata from excel file. Req: I want first my all test should run on same testdata ie. excel row, then all test with another row.
Resolution: tries to use @Factory with my @DataProvider
Issue: If I am using hardcore values in @dataProvider than it works fine. But when dynamically getting from excel it if giving me error: [ERROR] Caused by: java.lang.NullPointerException
package com;
import java.util.HashMap;
import utils.*;
import org.testng.annotations.*;
public class TestFile extends BaseClass {
public HashMap<String, String> values = new HashMap<String, String>();
@Test()
private void Test_01() {
System.out.println(values.get("Number"));
}
@Factory(dataProvider = "getDataSet")
public TestFile(HashMap<String, String> values) {
this.values = values;
}
@DataProvider
private static Object[] getDataSet() {
String sheetName = mContext.getCurrentXmlTest().getSuite().getParameters().get(Constants.BU_LEISURE_SHEET_NAME);
int i = 0;
Object[] dataSet = null;
HashMap<String, HashMap<String, String>> sheet = testData.get(sheetName);
dataSet = new Object[sheet.size()][1];
for (String row : sheet.keySet()) {
HashMap<String, String> rowValuesMap = new HashMap<>();
for (String columnName : sheet.get(row).keySet()) {
rowValuesMap.put(columnName, sheet.get(row).get(columnName));
}
dataSet[i] = rowValuesMap;
i++;
}
return dataSet;
}
}
Base Class
public class BaseClass extends DataReader {
@BeforeSuite
public static void setup(ITestContext context) throws IOException {
mContext = context;
// other code
}
}
Datareader class to read excel file
public class DataReader {
public static HashMap<String, HashMap<String, HashMap<String, String>>> testData = new HashMap<String, HashMap<String, HashMap<String, String>>>();
// other code
}
error log
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1:test (default-test) on project ATGDMAP: Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1:test failed: There was an error in the forked process [ERROR] java.lang.RuntimeException: java.lang.NullPointerException [ERROR] at org.testng.internal.MethodInvocationHelper.invokeMethodNoCheckedException(MethodInvocationHelper.java:49) [ERROR] at org.testng.internal.MethodInvocationHelper.invokeDataProvider(MethodInvocationHelper.java:131) [ERROR] at org.testng.internal.Parameters.handleParameters(Parameters.java:706) [ERROR] at org.testng.internal.FactoryMethod.invoke(FactoryMethod.java:151) [ERROR] at org.testng.internal.TestNGClassFinder.processFactory(TestNGClassFinder.java:223) [ERROR] at org.testng.internal.TestNGClassFinder.processMethod(TestNGClassFinder.java:179) [ERROR] at org.testng.internal.TestNGClassFinder.processClass(TestNGClassFinder.java:171) [ERROR] at org.testng.internal.TestNGClassFinder.(TestNGClassFinder.java:121) [ERROR] at org.testng.TestRunner.initMethods(TestRunner.java:370) [ERROR] at org.testng.TestRunner.init(TestRunner.java:271) [ERROR] at org.testng.TestRunner.init(TestRunner.java:241) [ERROR] at org.testng.TestRunner.(TestRunner.java:167) [ERROR] at org.testng.SuiteRunner$DefaultTestRunnerFactory.newTestRunner(SuiteRunner.java:663) [ERROR] at org.testng.SuiteRunner.init(SuiteRunner.java:260) [ERROR] at org.testng.SuiteRunner.(SuiteRunner.java:198) [ERROR] at org.testng.TestNG.createSuiteRunner(TestNG.java:1295) [ERROR] at org.testng.TestNG.createSuiteRunners(TestNG.java:1273) [ERROR] at org.testng.TestNG.runSuitesLocally(TestNG.java:1128) [ERROR] at org.testng.TestNG.runSuites(TestNG.java:1049) [ERROR] at org.testng.TestNG.run(TestNG.java:1017) [ERROR] at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:295) [ERROR] at org.apache.maven.surefire.testng.TestNGXmlTestSuite.execute(TestNGXmlTestSuite.java:84) [ERROR] at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:90) [ERROR] at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203) [ERROR] at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155) [ERROR] at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103) [ERROR] Caused by: java.lang.NullPointerException [ERROR] at com.TestFile.getDataSet(TestFile.java:27) [ERROR] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [ERROR] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) [ERROR] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [ERROR] at java.lang.reflect.Method.invoke(Method.java:498) [ERROR] at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:124) [ERROR] at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:74) [ERROR] at org.testng.internal.MethodInvocationHelper.invokeMethodNoCheckedException(MethodInvocationHelper.java:45) [ERROR] ... 25 more [ERROR] -> [Help 1] [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re-run Maven using the -X switch to enable full debug logging.
Upvotes: 1
Views: 284
Reputation: 14736
The problem lies in your test code.
You are getting the ITestContext
object via a @BeforeSuite
annotated method. But when you are using a factory coupled with a data provider, TestNG first finds the data provider associated with your factory method (the constructor in this case). Once the data provider method is found, it invokes it to get all the sets of data that is to be used to iterate and create test class instances. The data provider in your case is referring to a context object (mContext
in this case) that can be initialized only when the @BeforeSuite
method is invoked. The @BeforeSuite
method is not invoked until and unless the instance is created (which is what the factory method is attempting to do)
Here's the correct way of doing this.
The excel spreadsheet in my example has two sheets viz.,
The employee sheet has the following data in it
+--------+--------------------+
| name | email |
+--------+--------------------+
| John | [email protected] |
| Rajeev | [email protected] |
| Jack | [email protected] |
+--------+--------------------+
and the student sheet has the following data in it.
+-------+--------+
| name | rollNo |
+-------+--------+
| Surya | 1 |
| Rajni | 2 |
| Kamal | 3 |
+-------+--------+
The test class that uses the factory and a data provider which reads off of the above mentioned spreadsheet
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.testng.Assert;
import org.testng.ITestContext;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
public class TestclassSample {
private Map<String, String> data;
private static final String SHEET = "sheet";
private static final String FILENAME = "filename";
@Factory(dataProvider = "dp")
public TestclassSample(Map<String, String> data) {
this.data = data;
}
@Test
public void dataIsNotEmpty() {
System.err.println("Ensuring that " + data + " is not empty");
Assert.assertFalse(data.isEmpty());
}
@Test
public void dataHasAtleastTwoColumns() {
System.err.println("Ensuring that " + data + " has atleast 2 entries");
Assert.assertTrue(data.size() >= 2);
}
@DataProvider(name = "dp")
public static Object[][] getData(ITestContext context)
throws IOException, InvalidFormatException {
String filename = context.getCurrentXmlTest().getParameter(FILENAME);
if (filename == null || filename.trim().isEmpty()) {
throw new IllegalArgumentException("File name was not present as a parameter");
}
Workbook workbook = WorkbookFactory.create(new File(filename));
String sheet = context.getCurrentXmlTest().getParameter(SHEET);
if (sheet == null || sheet.trim().isEmpty()) {
throw new IllegalArgumentException("Sheet name was not present as a parameter");
}
Sheet worksheet = workbook.getSheet(sheet);
DataFormatter dataFormatter = new DataFormatter();
Row headingRow = worksheet.getRow(0);
List<String> heading = new ArrayList<>();
for (Cell cell : headingRow) {
heading.add(dataFormatter.formatCellValue(cell));
}
List<Map<String, String>> information = new ArrayList<>();
for (int i = 1; i < worksheet.getLastRowNum(); i++) {
Map<String, String> data = new HashMap<>();
int index = 0;
for (Cell cell : worksheet.getRow(i)) {
data.put(heading.get(index++), dataFormatter.formatCellValue(cell));
}
information.add(data);
}
Object[][] data = new Object[information.size()][1];
for (int i = 0; i < information.size(); i++) {
data[i] = new Object[] {information.get(i)};
}
workbook.close();
return data;
}
}
The testng suite xml looks like below
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="53358567_suite" parallel="false" verbose="2" group-by-instances="true">
<parameter name="sheet" value="student"/>
<parameter name="filename" value="src/test/resources/53358567.xlsx"/>
<test name="53358567_test">
<classes>
<class name="com.rationaleemotions.stackoverflow.qn53358567.TestclassSample"/>
</classes>
</test>
</suite>
The output is as below
...
... TestNG 7.0.0-beta1 by Cédric Beust ([email protected])
...
Ensuring that {name=Rajni, rollNo=2} has atleast 2 entries
Ensuring that {name=Rajni, rollNo=2} is not empty
Ensuring that {name=Surya, rollNo=1} has atleast 2 entries
Ensuring that {name=Surya, rollNo=1} is not empty
PASSED: dataHasAtleastTwoColumns
PASSED: dataIsNotEmpty
PASSED: dataHasAtleastTwoColumns
PASSED: dataIsNotEmpty
===============================================
53358567_test
Tests run: 4, Failures: 0, Skips: 0
===============================================
===============================================
53358567_suite
Total tests run: 4, Passes: 4, Failures: 0, Skips: 0
===============================================
Process finished with exit code 0
Upvotes: 1