0

Trying to learn how to use @Factory, but when I execute it in one of two ways, i get either an error or no tests get executed at all. I am invoking the XML file in Eclipse, by right-clicking on it, and selecting "Run As TestNG Suite".

With this XML file, the suite executes, but zero tests are picked up/executed:

<suite name="suite1" verbose="5">
    <test name="test1">
        <classes>
            <class name="qa.tests.MyFactory"/>
        </classes>
    </test>
</suite>

With this XML file, i get a test failure with an exception:

<suite name="suite1" verbose="5">
    <test name="test1">
        <packages>
            <package name="qa.tests" />
        </packages>
    </test>
</suite>

Error:

Can't invoke public void qa.tests.MyTest.testSample1(): either make it static or add a no-args constructor to your class

MyFactory.java class:

package qa.tests;
import org.testng.annotations.Factory;

public class MyFactory {
    @Factory
    public Object[][] dp() {
        Object[][] data = new Object[][] {
            { "1", "TestCase1", "Sample test 1" },
            { "2", "TestCase2", "Sample test 2" },
            { "3", "TestCase3", "Sample test 3" }
        };
        return data;
    }
}

MyTest.java class:

package qa.tests;
import org.testng.annotations.Test;
import static org.testng.Assert.*;

public class MyTest {
    private String num;
    private String name;
    private String desc;

     public MyTest(String num, String name, String desc) {
         this.num = num;
         this.name = name;
         this.desc = desc;
     }

     @Test()
     public void testSample1() {
         System.out.println(num + ", " + name + ", " + desc);
         assertTrue( true );
     }
}

What in the world am I doing incorrectly?

Greg
  • 3,861
  • 3
  • 23
  • 58
  • It seems like you want a [`@DataProvider`](http://testng.org/doc/documentation-main.html#parameters-dataproviders), not a `Factory`. A `Factory` is for dynamically constructing classes that *run* tests, not that are *being tested*. – dimo414 Jun 02 '15 at 05:01
  • Ultimately i will need a factory and dataprovider together, as data is coming from a spreadsheet, and I need ability to change the test name. Having said that, I am trying to understand and get factory to work first with a simple example. – Greg Jun 02 '15 at 15:52
  • That's fine, but your current example needs a `DataProvider`, not a `Factory`. There's numerous examples of [how to use a `Factory`](https://www.google.com/search?q=testng+factory+example) out there. – dimo414 Jun 02 '15 at 16:46
  • The problem is i was not returning one dimension object array as mentioned below. – Greg Jun 02 '15 at 17:23

3 Answers3

1

First of all ,a Factory should return a one dimension Object array. And that factory method should return instances of the test class that you are trying to execute.

So the factory will run your tests, if you change to this

public class MyFactory {
    @Factory
    public Object[] dp() {
        Object[] data = new Object[] {
            new MyTest("1", "TestCase1", "Sample test 1"), new Mytest("1", "TestCase1", "Sample test 1"), new MyTest("1", "TestCase1", "Sample test 1")
        };
        return data;
    }
}
Gosaka
  • 181
  • 7
0

As per this error : either make it static or add a no-args constructor to your class, Your MyTest class need to have public no-args contructor, Java will not add the default constructor as you already have parametrized constructor, i.e public MyTest(String num, String name, String desc)

UPDATE change your factory class

public class MyFactory {

@DataProvider(name = "MyData")
public static Object[][] dp(ITestContext context, Method m) throws Exception {

    return new Object[][] { new Object[] { "1", "TestCase1", "Sample test 1" }};
}

@Factory(dataProvider = "MyData")
public Object[] createInstances(String num, String name, String desc) {
    return new Object[] { new MyTest(num, name, desc) };
}
}
Ramesh Kotha
  • 8,266
  • 17
  • 66
  • 90
  • If I do that, then `@Factory` does not pass the values to `@Test` at all, I get nulls. [Invoker 37041917] Invoking qa.tests.MyTest.testSample1 null, null, null [Invoker 37041917] Invoking qa.tests.MyTest.testSample2 null, null, null – Greg Jun 01 '15 at 18:40
  • are you passing the values through parametrized constructor? – Ramesh Kotha Jun 01 '15 at 18:51
  • From what I understand, TestNG is supposed to do that automatically, based on all the examples i have found. – Greg Jun 01 '15 at 18:53
0
//Factory class supplying data to test
public class DataFactory {  

    @Factory
    public Object[] DataSupplier(){

        Object[] testData = new Object[3];
        testData[0] = new FactoryTest(1);
        testData[1] = new FactoryTest(2);
        testData[2] = new FactoryTest(3);
        return testData;
    }

}

//Test class
public class FactoryTest {

    int i;

    public FactoryTest(int i) {
        this.i = i;
    }

    @Test
    public void f() {
        System.out.println(i);
    }

}

Testng.xml

<suite name="Suite">
  <test name="Test">
    <classes>
      <class name="factorydata.DataFactory"/>
    </classes>
  </test> <!-- Test -->
</suite> 

Datafactory class supplies the test data by creating instances of the test class and passing parameters to FactoryTest class constructor.

FactoryTest class consumes the data from the datafactory.

In the testng.xml refer the class which has factory , in this case it is DataFactory.

This explains a simple working TestNg Factory annotation usage.