@Factory combined with @DataProvider BUG , please help

143 views
Skip to first unread message

Ben Mark

unread,
Jan 31, 2017, 6:06:24 AM1/31/17
to testng-users
Please look at the following code:

TestNG.version 6.10

import java.lang.reflect.Method;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;

public class ChildTestClass1 {
String a;
String b;
String c;
public ChildTestClass1(){}
@Factory(dataProvider = "dp")
public ChildTestClass1(String a1, String a2, String a3) {
a=a1;
b=a2;
c=a3;
}
@DataProvider(name = "dp", parallel = true)
public static Object[][] simpledataProvider(ITestContext context, ITestNGMethod method) throws Exception {

Object[][] data = new Object[][] { 
{ "DataA1", "DataA2", "DataA3" },
{ "DataB1", "DataB2", "DataB3" } };
return data;
}
@BeforeMethod()
public synchronized void init(Method m) throws Exception {
Thread.sleep(150);
System.out.println("before method:"+ m.getName());
System.out.println("Current thread id = " + Thread.currentThread().getId());
System.out.println("param a = " + this.a);
System.out.println("param b = " + this.b);
System.out.println("param c = " + this.c);
System.out.println("end Before method\n\n");
}
@Test(dataProvider = "dp")
public void TestMethod1(String a, String b, String c) throws InterruptedException {
synchronized (this) {
Thread.sleep(100);
System.out.println("Start test Method: TestMethod1");
System.out.println("param a = " + a);
System.out.println("param b = " + b);
System.out.println("param c = " + c);
System.out.println("Thread id = " + Thread.currentThread().getId());
System.out.println("end Test method: TestMethod1 \n\n\n");
}
}
}

When this code is executed, instead of getting TestMethod1 with 2 iterations, I'm getting 4.
Seems like it is executed twice from the @Factory, and then twice from the @Dataprovider

All I need is to initialize the class fields so that the @BeforeMethod will be able to process stuff




Thanks in advance,
~Ben

Vimal Raj

unread,
Jan 31, 2017, 6:24:55 AM1/31/17
to testng...@googlegroups.com
Remove the dataProvider from your @Test and remove the parameters from TestMethod1. That should help you.

--
You received this message because you are subscribed to the Google Groups "testng-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to testng-users+unsubscribe@googlegroups.com.
To post to this group, send email to testng...@googlegroups.com.
Visit this group at https://groups.google.com/group/testng-users.
For more options, visit https://groups.google.com/d/optout.

Ben Mark

unread,
Jan 31, 2017, 6:28:22 AM1/31/17
to testng-users
I can't I have a BaseClass dataprovider in my real problem where I have to have the ability to tell every testMethod how many iterations to run from an external dataSet
therefore I must have @Test connected to the dataprovider, since the dataprovider has the ITestNGMethod object that tells me via reflection which method called it.
To unsubscribe from this group and stop receiving emails from it, send an email to testng-users...@googlegroups.com.

Ben Mark

unread,
Jan 31, 2017, 6:30:19 AM1/31/17
to testng-users
I also have multiple test methods in multiple classes


On Tuesday, 31 January 2017 13:24:55 UTC+2, Vimal Raj wrote:
To unsubscribe from this group and stop receiving emails from it, send an email to testng-users...@googlegroups.com.

Cédric Beust ♔

unread,
Jan 31, 2017, 1:56:57 PM1/31/17
to testng...@googlegroups.com
The data provider on your constructor creates two instances of the test class, and then the data provider on the method will call that test method twice, hence four invocations.


-- 
Cédric


To unsubscribe from this group and stop receiving emails from it, send an email to testng-users+unsubscribe@googlegroups.com.

Ben Mark

unread,
Jan 31, 2017, 2:05:43 PM1/31/17
to testng-users, ced...@beust.com
True but I'm running all test-iterations in parallel, hence I need every test iteration to instantiate the class fields separately..
Do you have an elegant solution for such case?

Cédric Beust ♔

unread,
Jan 31, 2017, 2:07:47 PM1/31/17
to testng...@googlegroups.com
I guess I still don't understand your scenario. What's the point of using the same data provider for a class and then for a method inside that class?

Your method doesn't need to take any parameters: these parameters are the fields in the class.


-- 
Cédric


To unsubscribe from this group and stop receiving emails from it, send an email to testng-users+unsubscribe@googlegroups.com.

Ben Mark

unread,
Jan 31, 2017, 2:21:19 PM1/31/17
to testng-users, ced...@beust.com
My classes contain various test methods because every class represents a feature, and in that feature I run the required tests..
Every class inherits from  a base class, where in that base class I need a before every test method that will run some data processing based on my test iteration params.

infra structure:
I got one dataProvider located in the base class that is providing test iterations for multiple test methods located in various test classes,
I'm controlling this data via a custom xml file, where I execute it all via a testng.xml file using alot of reflection to get what I need.

Works like a charm, the only setback is the before method, since I'm running in parallel, every thread must instantiate the base class fields, besides, every thread is a standalone test running in parallel...


So my bottom line is:
I need to give the exact values from every iteration that holds different number of parameters that is injected from the dataProvider into the tests, to also be injected into their before method..

Thanks in advance cedric,
~Ben

⇜Krishnan Mahadevan⇝

unread,
Jan 31, 2017, 11:22:04 PM1/31/17
to testng...@googlegroups.com
Ben,

Like every one else have mentioned before, Coupling a Factory driven data provider with a test class that also is driven by a data provider is NOT what you should be doing.

Would the following example give you so lead into how you may want to approach your problem ? 


public class DemoTest {

    @BeforeMethod
    public void beforeMethod(Method method, Object[] params) {
        //I am simulating my beforeMethod massaging my test data so that it can be
        //consumed by my data driven tests.
        for (int i = 0; i < params.length; i++) {
            params[i] = ((String) params[i]).toUpperCase();
        }
    }

    @Test (dataProvider = "dp")
    public void testMethod(String a, String b) {
        Reporter.log("a = [" + a + "], b = [" + b + "]", true);
        Assert.assertTrue(a.toUpperCase().equals(a));
        Assert.assertTrue(b.toUpperCase().equals(b));
    }

    @DataProvider (name = "dp")
    public Object[][] getData() {
        return new Object[][] {
            {"india", "cricket"},
            {"srilanka", "cricket"}
        };
    }
}

You will have to get rid of the Factory annotation and its coupling with the data provider, because the Factory annotation is to be used ONLY when you want TestNG to create Test Class instances by invoking its Non default constructor, pass it some values and then have all the test methods in the Test Class use the parameters for their tests. 
A good example for this would be : Lets say you have a test class that has tests for Login, Compose Email, Check Sent Folder and all these tests have to run for every set of username/password combos, thats when you would go for a Factory + Data Provider combo.

Unfortunately I am still not able to comprehend what is the use case that you are trying to solve. Maybe you could help share some mock test code that can explain your use case in a better fashion ?


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/
My Technical Scribbings @ http://rationaleemotions.wordpress.com/

To unsubscribe from this group and stop receiving emails from it, send an email to testng-users+unsubscribe@googlegroups.com.

Ben Mark

unread,
Feb 1, 2017, 5:34:05 AM2/1/17
to testng-users
Krishnan, you made my day, thanks dude.
Didn't know beforeMethod has an option to get Object [] params as an argument and is also being injected from the dataProvider

cheers mate,
~Ben
Reply all
Reply to author
Forward
0 new messages