Launch multiple test with the same data provider (lazy iterator)

1,962 views
Skip to first unread message

anavas57

unread,
Sep 19, 2010, 8:43:50 PM9/19/10
to testng-users
I've built a Lazy Iterator that reads data from an excel file one row
at a time. The iterator returns one row at a time with up to 7
different fields to the first @Test. But what I need is the avility to
use the same data in multiple @Tests like shown below

@Test(dataProvider = "runner")
public void firstTest(String[] obj) {
}

@Test(dataProvider = "runner")
public void secondTest(String[] obj) {
}

@Test(dataProvider = "runner")
public void thirdTest(String[] obj) {
}

Same data should be used in first, second and third test before the
next row is called in. I've tried with a super @Test
public class A {
@Test
@Test
@Test
}

But it's not working. I've also tried using only one@Test like in

@Test(dataProvider = "runner")
public void firstTest(String[] obj) {
}
public void secondTest(String[] obj) {
}
public void thirdTest(String[] obj) {
}

An still not working

Thanks in advance

See below current code with only one @Test

public class testngDLExcel extends SeleneseTestCase {
@DataProvider(name = "runPlanSerial")
public Iterator<Object> createSerialPlan() {
return new SimpleIterator();
}

@DataProvider(name = "generate-data")
public Object[][] getTableArray() {
String[][] tabArray = null;
File fp = new File("test\\Resources\\Data\\Data2.xls");
String tableName = "imdbTestData1";
try{
Workbook workbook = Workbook.getWorkbook(fp);
Sheet sheet = workbook.getSheet(0);
int startRow,startCol, endRow, endCol,ci,cj;
Cell tableStart=sheet.findCell(tableName);
startRow=tableStart.getRow();
startCol=tableStart.getColumn();
Cell tableEnd= sheet.findCell(tableName, startCol
+1,startRow+1, 100, 64000, false);
endRow=tableEnd.getRow();
endCol=tableEnd.getColumn();
tabArray=new String[endRow-startRow-1][endCol-
startCol-1];
ci=0;
for (int i=startRow+1;i<endRow;i++,ci++){
cj=0;
for (int j=startCol+1;j<endCol;j++,cj++){
tabArray[ci]
[cj]=sheet.getCell(j,i).getContents();
}
}
}

catch (Exception e) {
System.out.println("error in getTableArray()");
}
return(tabArray);
}

public class SimpleIterator implements Iterator<Object> {
Object[][] retObjArray = getTableArray();
private int currentIndex;

public SimpleIterator() {
currentIndex = 0;
}

public boolean hasNext() {
System.out.println("Has Next: " + currentIndex);
return currentIndex < retObjArray.length;
}

public Object next() {
int index = currentIndex;
currentIndex++;
System.out.println("Next " + index);
String[] data = null;
data = new String[retObjArray[index].length];
for (int j = 0; j<retObjArray[index].length; j++ ) {
data[j] = (String) retObjArray[index][j];
System.out.println("Next data returned is " +
data[j]);
}
return new Object[]{data};
}

public void remove() {
throw new UnsupportedOperationException();
}
}

@DataProvider(name = "runner", parallel=true)
public Iterator<Object> createParallelPlan() {
return new SimpleIterator();
}

@Test(dataProvider = "runner")
public void testParallel(String[] obj) {
int objLength = obj.length;
for (int i=0;i<obj.length; i++){
System.out.print(" " + obj[i]+"\t");
}
System.out.println();
}
}

Cédric Beust ♔

unread,
Sep 20, 2010, 12:36:22 PM9/20/10
to testng...@googlegroups.com
Are you sure you are returning a brand new iterator in your data provider?

If you initialize your iterator in a field declaration and then return that field in your data provider, then subsequent invocations of your data provider will produce an empty iterator since it will have run past the end...

Make sure you "new" your lazy iterator in the data provider and it should work.

-- 
Cédric



--
You received this message because you are subscribed to the Google Groups "testng-users" group.
To post to this group, send email to testng...@googlegroups.com.
To unsubscribe from this group, send email to testng-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/testng-users?hl=en.




--
Cédric


anavas57

unread,
Sep 20, 2010, 4:36:08 PM9/20/10
to testng-users

Hi Cedric,

Thanks for your answer. I've reviewed the code and have noticed I was
treating "data" as a String. "Data" - now an Object - is returning as
a "new" Object[] (data) and it's bringing back the expected
information to @Test

Problem now is how to use the same data returned in each iteration in
different tests that will be running sequencially?

As you can see below, Address and ZipCode will be used in the Landing
page. Then, once I move to the next page, called Dispatch page, I will
use phone information (NPA, NXX and Suffix) and/or City, State
(depending on what's showing up.

I would like to use the same data in different @Test (or at least in
different Methods) as a way to isolate the tests and to improve my
reporting.

What's happening now is that, once enterAddressPhone is executed, the
iterator is bringing back the second set of date without waiting until
the other methods are executed.

See below an example from my code:

@Test(description="Navigate Digital Commerce", dataProvider =
"runner")
public void enterAddressPhone(Object[] obj) throws
InterruptedException{
String Address = (String) obj[0];
String Apartment = (String) obj[1];
String City = (String) obj[2];
String State = (String) obj[3];
String ZipCode = (String) obj[4];
String NPA = (String) obj[5];
String NXX = (String) obj[6];
String Suffix = (String) obj[7];

for (int second = 0;; second++) {
if (second >= 60) break;
try { if (selenium.isVisible("dl_addressInput")) {
selenium.type("dl_addressInput", Address);
selenium.type("dl_zipCodeInput", ZipCode);
selenium.click("compareNow");
selenium.waitForPageToLoad("240000");
break; }
}
catch (Exception e) {};}
Thread.sleep(1000);
}
public void phoneEntrySubmit(String NPA, String NXX, String Suffix)
throws InterruptedException{

// Verify if phone_entry_submit pop-up is present
for (int second = 0;; second++) {
if (second >= 30) break;
try { if (selenium.isVisible("phone_entry_submit"))
{
boolean ldata = true;
if ((NPA.length()!= 3)) ldata = false;
if ((NXX.length()!= 3)) ldata = false;
if ((Suffix.length()!= 4)) ldata = false;
if (ldata){
selenium.type("npa", NPA);
selenium.type("nxx", NXX);
selenium.type("suffix", Suffix);}
selenium.click("phone_entry_submit");
break; }
} catch (Exception e) {}
Thread.sleep(1000);
}
}

Cédric Beust ♔

unread,
Sep 20, 2010, 4:46:03 PM9/20/10
to testng...@googlegroups.com
I think you are mixing up two different things. The problem you are facing seems to be more about ordering of tests than providing the same data to different tests.

How to solve your problem:

@DataProvider
public Iterator<Object[]> dp() {
  return new MyIterator(...);
}

Then, depending on what interleaving you want:

@Test(dataProvider = "dp")
public void f1(args) {
  ...
}

@Test(dataProvider = "dp")
public void f2(args) {
  ...
}

or

@Test(dataProvider = "dp")
public void f(arg) {
  f1(args);
  f2(args);
}

and f1 and f2 are regular methods (not @Test).

-- 
Cédric





--
You received this message because you are subscribed to the Google Groups "testng-users" group.
To post to this group, send email to testng...@googlegroups.com.
To unsubscribe from this group, send email to testng-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/testng-users?hl=en.




--
Cédric


anavas57

unread,
Sep 21, 2010, 12:18:49 AM9/21/10
to testng-users
Finally got it right!!! Thanks so much Cedric. Like you said I was
mixing different concepts and, as expected, making no sense in my
code. Sugestion below it's working fine now and will be my choice at
this point.

Ahmad Tavakoli

unread,
May 23, 2012, 2:59:34 PM5/23/12
to testng...@googlegroups.com
Hi Cedric,

I have the other problem, I want to provide the same data coming from the dataprovider to a group of tests. I don't want the same data created over and over again from the dataprovider. is there any way for that?

thanks
To unsubscribe from this group, send email to testng-users+unsubscribe@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/testng-users?hl=en.




--
Cédric


Cédric Beust ♔

unread,
May 23, 2012, 3:02:46 PM5/23/12
to testng...@googlegroups.com
On Wed, May 23, 2012 at 11:59 AM, Ahmad Tavakoli <ahmadta...@gmail.com> wrote:
Hi Cedric,

I have the other problem, I want to provide the same data coming from the dataprovider to a group of tests. I don't want the same data created over and over again from the dataprovider. is there any way for that?

Why not store that data in a field and return that field for subsequent invocations?

-- 
Cédric

Ahmad Tavakoli

unread,
May 23, 2012, 3:18:41 PM5/23/12
to testng...@googlegroups.com

The data is to big to be stored in memory, I am using lazy data provider to create them in time of running.

Cédric Beust ♔

unread,
May 23, 2012, 3:26:52 PM5/23/12
to testng...@googlegroups.com
So you don't want to calculate the data every time but you can't cache it either... Isn't that an impossible problem?  :-)

How about using an intermediate solution, caching some elements but not all? Either a fixed percentage, or the ones that are the most expensive to calculate (if there's such a thing)

-- 
Cédric




--
You received this message because you are subscribed to the Google Groups "testng-users" group.
To view this discussion on the web visit https://groups.google.com/d/msg/testng-users/-/T3zNwqKAxmgJ.

To post to this group, send email to testng...@googlegroups.com.
To unsubscribe from this group, send email to testng-users...@googlegroups.com.

Ahmad Tavakoli

unread,
May 23, 2012, 3:27:30 PM5/23/12
to testng...@googlegroups.com

 My dataprovider creates objects which all test are going to read it to verify something, but dataprovider is called once for each test and creates the same object for each test. since there is going to be a set of objects created, which are going to be tested, If there is a way to pass the same object to each test, that would save a lot of time.

Krishnan Mahadevan

unread,
May 23, 2012, 3:36:55 PM5/23/12
to testng...@googlegroups.com
Would you be able to try out factories coupled with data providers and see if that can help solve your issue?

I havent tried this to be absolutely sure that this can be an option but just thought of suggesting this. 

You could have a @Factory method instantiate Test classes by using a data provider. That way every instance of the test class can be fed the same set of data which can be consumed by the individual Test methods which are part of the test class. 

Would that work?
--
You received this message because you are subscribed to the Google Groups "testng-users" group.
To view this discussion on the web visit https://groups.google.com/d/msg/testng-users/-/gF0D2ckkfMMJ.

To post to this group, send email to testng...@googlegroups.com.
To unsubscribe from this group, send email to testng-users...@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/testng-users?hl=en.


--
Thanks & Regards
Krishnan Mahadevan

"All the desirable things in life are either illegal, expensive, fattening or in love with someone else!"
My Scribblings @ http://wakened-cognition.blogspot.com/

Ahmad Tavakoli

unread,
May 24, 2012, 10:01:09 AM5/24/12
to testng...@googlegroups.com
 Thanks, I tried this method and it worked to some extent. Still, what it does is that it creates factories with a lazy data provider one by one, but it does not start tests inside factories unless it created all of the factories. so it keeps storing all factories inside memory, when it has all of them, it starts running tests inside factories.

Is there a way that it can start running tests once it creates a factory?




On Wednesday, May 23, 2012 3:36:55 PM UTC-4, Krishnan wrote:
Would you be able to try out factories coupled with data providers and see if that can help solve your issue?

I havent tried this to be absolutely sure that this can be an option but just thought of suggesting this. 

You could have a @Factory method instantiate Test classes by using a data provider. That way every instance of the test class can be fed the same set of data which can be consumed by the individual Test methods which are part of the test class. 

Would that work?

On Thursday, May 24, 2012, Ahmad Tavakoli wrote:

 My dataprovider creates objects which all test are going to read it to verify something, but dataprovider is called once for each test and creates the same object for each test. since there is going to be a set of objects created, which are going to be tested, If there is a way to pass the same object to each test, that would save a lot of time.

On Wednesday, May 23, 2012 3:18:41 PM UTC-4, Ahmad Tavakoli wrote:

The data is to big to be stored in memory, I am using lazy data provider to create them in time of running.


On Wednesday, May 23, 2012 3:02:46 PM UTC-4, Cédric Beust ♔ wrote:
On Wed, May 23, 2012 at 11:59 AM, Ahmad Tavakoli <ahmadta...@gmail.com> wrote:
Hi Cedric,

I have the other problem, I want to provide the same data coming from the dataprovider to a group of tests. I don't want the same data created over and over again from the dataprovider. is there any way for that?

Why not store that data in a field and return that field for subsequent invocations?

-- 
Cédric

--
You received this message because you are subscribed to the Google Groups "testng-users" group.
To view this discussion on the web visit https://groups.google.com/d/msg/testng-users/-/gF0D2ckkfMMJ.
To post to this group, send email to testng...@googlegroups.com.
To unsubscribe from this group, send email to testng-users+unsubscribe@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/testng-users?hl=en.
Reply all
Reply to author
Forward
0 new messages