How to pass bean class to a test method in testng? - selenium

I have an Excel Util which reads all the data from excel sheet. The excel sheet has 10 columns like time, sourceType, tid, message, severity,
lastModify, entityName, operationType, replayId, recordIds.
My DataProvider has code something like this which returns all the 10 columns and their values.
#DataProvider(name="googleData")
public static Object[][] testData() {
String filePath = "/Users/TestUser/Workspace/FixProject/ExcelCheck/src/test/resources/excelreader.xlsx";
Object[][] arrayObject = excelFileUtils.getExcelData(filePath, "excelreader");
return arrayObject;
}
In My TestMethod, I have to pass all these 10 columns or else it wont allow me to run. Instead I want to create a Bean Class and pass something like this to my test method
#Test(dataProvider = "googleData", dataProviderClass = DataProviders.class)
public void testGoogleData(BeanClass object) {
System.out.println(object.getTid());
}
How do we achieve this?

Using the dataProvider you have, your test method is going to run 10 times for each object in the array.
What you can do is to create an object, convert your dataProvider into that object and than use it your test method code.
Object myDataHelper = null;
#Test()
public void testGoogleData(BeanClass object) {
myDataHelper = convertDataProviderToObject();
// use it here in a for/for each loop
System.out.println(object.getTid());
}

public static Object[][] read_excel(String Sheet_Name) throws Exception
{
File obj = new File("./src/main/java/com/Demo/TestData/Test_Data.xlsx");
FileInputStream fis = new FileInputStream(obj);
XSSFWorkbook wb = new XSSFWorkbook(fis);
XSSFSheet sheet = wb.getSheet(Sheet_Name);
int row_number = sheet.getLastRowNum();
int column_number = sheet.getRow(0).getLastCellNum();
Object data[][] = new Object[row_number][column_number];
wb.close();
for(int i=0; i<row_number; i++)
{
for(int j=0; j<column_number; j++)
{
data[i][j] = sheet.getRow(i + 1).getCell(j).toString();
}
}
return data;
}
#DataProvider
public Object[][] getDataFromExcel() throws Exception
{ Object[][] data = Utility.read_excel("Admin_Credentials");//Sheet name
return data;
}
#Test(dataProvider="getDataFromExcel")

It is supported in QAF-TestNG extension. You can have one or more complex object argument in your test method while using inbuilt or custom data provider. For excel your code may look like below:
#QAFDataProvider(dataFile = "resources/data/googletestdata.xls")
#Test
public void testGoogleData(BeanClass object) {
System.out.println(object.getTid());
}
For custom data provider it may look like below:
#QAFDataProvider
#Test(dataProvider = "googleData", dataProviderClass = DataProviders.class)
public void testGoogleData(BeanClass object) {
System.out.println(object.getTid());
}
You need to make sure that,properties name in your bean class must match column names (in any order). When using custom data provider you need to return Iterator for List of Map<String, Object> or Object[][] having Map, refer few example if you required to create custom data provider.

Related

java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to java.util.List

I have a List<List<String>> dataTableList and I would like to get a specific list from there and put it on my List<String> dataList so that I could loop through that specific lists' value and alter it.
However, whenever I try to do that,I always get an error of:
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to java.util.List.
Here's a sample of how I am trying to assign a specific list from dataTableList to dataList:
//First I looped through the List of Lists and called each list fetched as dataList
for(List<String> dataList : getTryLang().getDataTableList()){
//then, I created an iterator to be used later when I return the List I fetched with altered value
int iter = 0;
//next, I created a for-loop to iterate through the values of the List the I feched
for(int x; x < dataList.size(); x++){
//here, I formatted each value to amount or currency format.
dataList.set(x, getDataConvert().convertAmount(dataList.get(x)));
//finally, after I formatted everything, I returned it or set it to the specific index it's been located before
getTryLang().getDataTableList().set(iter, dataList);
}
iter++;
}
EDIT:
Here's my code and I modified some of it and didn't include some so that I could focus on expressing where the problem occurs.
Here's my TryLang.java:
#ManagedBean
#SessionScoped
public class TryLang implements Serializable {
public TryLang() {}
//declare
private List<List<String>> dataTableList;
//getter setter
public List<List<String>> getDataTableList() {
return dataTableList == null ? dataTableList = new ArrayList<>() : dataTableList;
}
public void setDataTableList(List<List<String>> dataTableList) {
this.dataTableList = dataTableList;
}
}
Then here's my BookOfAccountsController.java:
#ManagedBean
#RequestScoped
public class BooksOfAccountsController implements Serializable {
public BooksOfAccountsController() {}
//declare
#ManagedProperty(value = "#{dataConvert}")
private DataConvert dataConvert;
#ManagedProperty(value = "#{tryLang}")
private TryLang tryLang;
//getter setter NOTE: I wouldn't include other getter setters to shorten the code here :)
public TryLang getTryLang() {
return tryLang == null ? tryLang = new TryLang() : tryLang;
}
public void setTryLang(TryLang tryLang) {
this.tryLang = tryLang;
}
//I would just go straight to the method instead
public void runBooksOfAccounts() throws SystemException, SQLException {
//So there are dbCons here to connect on my DB and all. And I'll just go straight on where the List<List<String>> is being set
//Here's where the List<List<String>> is being set
getTryLang().setDataTableList(getCemf().getFdemf().createEntityManager().createNativeQuery("SELECT crj.* FROM crj_rep crj").getResultList());
getTryLang().setDataTableColumns(getCemf().getFdemf().createEntityManager().createNativeQuery("SELECT col.column_name FROM information_schema.columns col WHERE table_schema = 'public' AND table_name = 'crj_rep'").getResultList());
for (int x = 0; x < getTryLang().getDataTableColumns().size(); x++) {
try {
Integer.parseInt(getTryLang().getDataTableColumns().get(x));
getTryLang().getDataTableColumns().set(x, getDataConvert().accountCodeConvert(getTryLang().getDataTableColumns().get(x)));
//then here is where the error points at
for (List<String> dataList : getTryLang().getDataTableList()) {
try{
int iter = 0;
dataList.set(x, getDataConvert().convertAmount(new BigDecimal(dataList.get(x))));
getTryLang().getDataTableList().set(iter, dataList);
iter++;
}catch(ClassCastException ne){
System.out.println("cannot convert " + ne);
}
}
} catch (NumberFormatException ne) {
//print the error
}
}
}
}

Read different values from Excel file every time when test case runs

I have create a excel file with some codes and I am using RepeatRule class to execute my test case 100 times in one class. I need to use different 100 codes every time the test will run rather than using the same code again and again. Below is my code
#Test
#Repeat(2)
public void Test() throws Exception {
Success.setUp();
Success.allowcokkies();
//Success.Ecoomerecemain();
File source = new File("/Users/test/Downloads/Voucher-codes.xlsx");
FileInputStream input = new FileInputStream(source); // Read Excel Data
XSSFWorkbook wb = new XSSFWorkbook(input);
XSSFSheet sheet = wb.getSheetAt(0);
int noOfColumns = sheet.getRow(0).getLastCellNum();
System.out.println(noOfColumns);
String[] Headers = new String[noOfColumns];
int j=0;
Headers[j] = sheet.getRow(0).getCell(j).getStringCellValue();
Success.getDriver().findElement(By.xpath("//*[#id=\"code\"]")).sendKeys(sheet.getRow(0).getCell(j).getStringCellValue());// Enter Coupon
Thread.sleep(2000);
}
#After
public void testdown()
{
Success.getDriver().quit();
This is repeat class code:
public class RepeatRule implements TestRule {
public static class RepeatStatement extends Statement {
private final Statement statement;
private final int repeat;
public RepeatStatement(Statement statement, int repeat) {
this.statement = statement;
this.repeat = repeat;
}
#Override
public void evaluate() throws Throwable {
for (int i = 0; i < repeat; i++) {
statement.evaluate();
}
}
}
#Override
public Statement apply(Statement statement, Description description) {
Statement result = statement;
Repeat repeat = description.getAnnotation(Repeat.class);
if (repeat != null) {
int times = repeat.value();
result = new RepeatStatement(statement, times);
}
return result;
}
}
How can I read different codes every time while using Repeat rule?
The easy way to do this is a JUnit 5 parameterized test. Save your Excel sheet as csv and use the following test method:
#ParameterizedTest
#CsvFileSource(resources = "/Users/test/Downloads/Voucher-codes.csv", numLinesToSkip = 1)
void testVoucher(String coupon) {
...
Success.getDriver().findElement(By.xpath("//*[#id=\"code\"]")).sendKeys(coupon);// Enter Coupon
...
}
Parameterized tests are possible with JUnit 4 as well. An example is described in the JUnit Wiki. You can even use the Excel sheet as a data provider with your POI code.
Another solution would be using #BeforeEach, where you could update a coupon field couponIndex in your test class and access the right row by the value of this field.
Success.getDriver().findElement(By.xpath("//*[#id=\"code\"]")).sendKeys(sheet.getRow(couponIndex).getCell(j).getStringCellValue());// Enter Coupon
I would recommend using a parameterized test.

how can we pass more than one dataprovider in to a single Test

I want to read data from an excel file having two sheet named as "LoginPo" and "LoginData". So how can i achieve this and use these two Data providers return value in my test like below.What will be the correct approach?Please help
#DataProvider(name="DP1")
public Object[][] createData1() throws Exception
{
Object[][] arr = getCSV("C://Users//purnendu_rath//Desktop//Login.csv","LoginPO");
return arr;
}
#DataProvider(name="DP2")
public Object[][] createData() throws Exception
{
Object[][] arr = getCSV("C://Users//purnendu_rath//Desktop//Login.csv","LoginData");
return arr;
}
#Test(DataProvider="DP1","Dp2")
public void accountLogin(//pass teh value here of DP1 and DP2)
{
//Coding for testcase
}

Jackson one item parse

I'm trying to parse openweathermap.org api
WeatheModel.java
public class WeatherModel {
private ListDays[] listDays;
#JsonProperty("list")
public ListDays[] getListDays() {
return listDays;
}
and two classes here http://pastebin.com/vySPfRSS
Main.java
public class Main {
public static final String WEATHER = "JSON from http://api.openweathermap.org/data/2.5/forecast/daily?q=London&mode=json&units=metric&cnt=7"
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
WeatherModel rootNode = mapper.readValue(WEATHER, WeatherModel.class);
How to get one (now it a list of 7 items ) item from WeatherModel?
Simply use the index to access object from an array.
ListDays[] listDays = rootNode.getListDays();
ListDays first = listDays[0];
ListDays second = listDays[1];
Arrays are sequences of objects and in the case above you describe an array of 7 ListDays. The first object uses index 0, the second object uses index 1 and so on. The [0] simply means that you retrieve the first object from the array. The length of the array can be determined by invoking listDays.length.
To loop through all of the elements you can use a for-loop.
for (ListDays l : listDays) {
// Here you have access to one ListDays-object. It is called l.
l.doStuff...
}

Mono.CSharp: how do I inject a value/entity *into* a script?

Just came across the latest build of Mono.CSharp and love the promise it offers.
Was able to get the following all worked out:
namespace XAct.Spikes.Duo
{
class Program
{
static void Main(string[] args)
{
CompilerSettings compilerSettings = new CompilerSettings();
compilerSettings.LoadDefaultReferences = true;
Report report = new Report(new Mono.CSharp.ConsoleReportPrinter());
Mono.CSharp.Evaluator e;
e= new Evaluator(compilerSettings, report);
//IMPORTANT:This has to be put before you include references to any assemblies
//our you;ll get a stream of errors:
e.Run("using System;");
//IMPORTANT:You have to reference the assemblies your code references...
//...including this one:
e.Run("using XAct.Spikes.Duo;");
//Go crazy -- although that takes time:
//foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
//{
// e.ReferenceAssembly(assembly);
//}
//More appropriate in most cases:
e.ReferenceAssembly((typeof(A).Assembly));
//Exception due to no semicolon
//e.Run("var a = 1+3");
//Doesn't set anything:
//e.Run("a = 1+3;");
//Works:
//e.ReferenceAssembly(typeof(A).Assembly);
e.Run("var a = 1+3;");
e.Run("A x = new A{Name=\"Joe\"};");
var a = e.Evaluate("a;");
var x = e.Evaluate("x;");
//Not extremely useful:
string check = e.GetVars();
//Note that you have to type it:
Console.WriteLine(((A) x).Name);
e = new Evaluator(compilerSettings, report);
var b = e.Evaluate("a;");
}
}
public class A
{
public string Name { get; set; }
}
}
And that was fun...can create a variable in the script's scope, and export the value.
There's just one last thing to figure out... how can I get a value in (eg, a domain entity that I want to apply a Rule script on), without using a static (am thinking of using this in a web app)?
I've seen the use compiled delegates -- but that was for the previous version of Mono.CSharp, and it doesn't seem to work any longer.
Anybody have a suggestion on how to do this with the current version?
Thanks very much.
References:
* Injecting a variable into the Mono.CSharp.Evaluator (runtime compiling a LINQ query from string)
* http://naveensrinivasan.com/tag/mono/
I know it's almost 9 years later, but I think I found a viable solution to inject local variables. It is using a static variable but can still be used by multiple evaluators without collision.
You can use a static Dictionary<string, object> which holds the reference to be injected. Let's say we are doing all this from within our class CsharpConsole:
public class CsharpConsole {
public static Dictionary<string, object> InjectionRepository {get; set; } = new Dictionary<string, object>();
}
The idea is to temporarily place the value in there with a GUID as key so there won't be any conflict between multiple evaluator instances. To inject do this:
public void InjectLocal(string name, object value, string type=null) {
var id = Guid.NewGuid().ToString();
InjectionRepository[id] = value;
type = type ?? value.GetType().FullName;
// note for generic or nested types value.GetType().FullName won't return a compilable type string, so you have to set the type parameter manually
var success = _evaluator.Run($"var {name} = ({type})MyNamespace.CsharpConsole.InjectionRepository[\"{id}\"];");
// clean it up to avoid memory leak
InjectionRepository.Remove(id);
}
Also for accessing local variables there is a workaround using Reflection so you can have a nice [] accessor with get and set:
public object this[string variable]
{
get
{
FieldInfo fieldInfo = typeof(Evaluator).GetField("fields", BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldInfo != null)
{
var fields = fieldInfo.GetValue(_evaluator) as Dictionary<string, Tuple<FieldSpec, FieldInfo>>;
if (fields != null)
{
if (fields.TryGetValue(variable, out var tuple) && tuple != null)
{
var value = tuple.Item2.GetValue(_evaluator);
return value;
}
}
}
return null;
}
set
{
InjectLocal(variable, value);
}
}
Using this trick, you can even inject delegates and functions that your evaluated code can call from within the script. For instance, I inject a print function which my code can call to ouput something to the gui console window:
public delegate void PrintFunc(params object[] o);
public void puts(params object[] o)
{
// call the OnPrint event to redirect the output to gui console
if (OnPrint!=null)
OnPrint(string.Join("", o.Select(x => (x ?? "null").ToString() + "\n").ToArray()));
}
This puts function can now be easily injected like this:
InjectLocal("puts", (PrintFunc)puts, "CsInterpreter2.PrintFunc");
And just be called from within your scripts:
puts(new object[] { "hello", "world!" });
Note, there is also a native function print but it directly writes to STDOUT and redirecting individual output from multiple console windows is not possible.