Let’s learn about the TestNG @Factory annotation which allows tests to be created at runtime depending on certain data-sets or conditions.
Table of Contents 1. When to use testng factory 2. Basic testng factory example 3. TestNG factory - test parameters 4. TestNG @Factory with @DataProvider 5. TestNG @Factory - dependent tests
1. When to use testng factory
Sometimes we may need to run a set of tests with different data values. To achieve this we may define a separate set of tests inside a suite in the testng XML and test the required scenario. The problem with this approach is that if you get an extra set of data, you will need to redefine the test.
TestNG solves this problem by providing the @Factory
annotation feature. Factory in TestNG defines and creates tests dynamically at runtime.
It’s mandatory that a factory method should return an array of Object
class i.e. Object []
.
2. Basic testng factory example
Let’s create a sample program using the @Factory
annotation of TestNG to understand how to use factory.
public class SimpleTest { @Test public void simpleTest() { System.out.println("Simple Test Method."); } } public class SimpleTestFactory { @Factory public Object[] factoryMethod() { return new Object[] { new SimpleTest(), new SimpleTest() }; } }
The preceding class defines a factory method inside it. A factory method is defined by declaring @Factory
above the respective test method.
Let’s run the factory now.
Simple Test Method. Simple Test Method. PASSED: simpleTest PASSED: simpleTest
As you can see in the preceding test results, the test method from the SimpleTestFactory
class was executed two times. The execution is based on the Object
array returned by the factory method. As the said method returns two objects of the SimpleTest
class, TestNG looks inside the specified returned object and executes all the test methods inside it. In this case, as there was only one test method, TestNG executes the respective test method.
3. TestNG factory parameters
One of the main advantage of using the factory methods is that you can pass parameters to test classes while initializing them. These parameters can then be used across all the test methods present in the said classes.
public class SimpleTest { private int param; public SimpleTest(int param) { this.param = param; } @Test public void testMethodOne() { int opValue = param + 1; System.out.println("Test method one output: " + opValue); } @Test public void testMethodTwo() { int opValue = param + 2; System.out.println("Test method two output: " + opValue); } } public class SimpleTestFactory { @Factory public Object[] factoryMethod() { return new Object[] { new SimpleTest(0), new SimpleTest(1) }; } }
The constructor of the previous test class takes one argument as an integer, which is assigned to a local variable param. This variable then is used in the two test methods present in the test class. Each of the test methods adds a value to param and prints it to the console on execution.
Let’s run the test now.
Test method one output: 2 Test method one output: 1 Test method two output: 3 Test method two output: 2 PASSED: testMethodOne PASSED: testMethodOne PASSED: testMethodTwo PASSED: testMethodTwo
As you can see from the preceding test results, each of the test methods are executed two times each. The parameters passed while initializing the test class are used by the test methods and the console shows the respective output.
4. TestNG @Factory and @DataProvider
The @DataProvider
feature can also be used with the @Factory
annotation for creating tests at runtime. This can be done by declaring the @Factory
annotation on a constructor of a class or on a regular method.
public class DataProviderTest { private int param; @Factory(dataProvider = "dataMethod") public DataProviderTest(int param) { this.param = param; } @DataProvider public static Object[][] dataMethod() { return new Object[][] { { 0 }, { 1 } }; } @Test public void testMethodOne() { int opValue = param + 1; System.out.println("Test method one output: " + opValue); } @Test public void testMethodTwo() { int opValue = param + 2; System.out.println("Test method two output: " + opValue); } }
The preceding class is similar to the test class, which we used earlier. The constructor of the test class is annotated with the @Factory
annotation. This annotation uses a DataProvider method named dataMethod for providing values to the constructor of the test class. The DataProvider method returns a double object array in which the first array represents the dataset, which decides the number of times the test will be iterated, whereas the second array is the actual parameter value that will be passed to the test method per iteration. The said double object array contains two datasets with values 0 and 1.
Let’s run the test now.
Test method one output: 2 Test method one output: 1 Test method two output: 3 Test method two output: 2 PASSED: testMethodOne PASSED: testMethodOne PASSED: testMethodTwo PASSED: testMethodTwo
5. TestNG @Factory – dependent tests
We have seen different examples of factory implementation so far. Let’s see how a dependency method is executed when used with the factory class.
public class DependencyTest { private int param; public DependencyTest(int param) { this.param = param; } @Test(dependsOnMethods = { "testMethodTwo" }) public void testMethodOne() { System.out.println("Test method one with param values: " + this.param); } @Test public void testMethodTwo() { System.out.println("Test method two with param values: " + this.param); } } public class SimpleTestFactory { @Factory public Object[] factoryMethod() { return new Object[] { new DependencyTest(1), new DependencyTest(2) }; } }
This class contains two test methods testMethodOne
and testMethodTwo
, where testMethodOne
depends on testMethodTwo
. The constructor of the class takes one argument as integer, and sets its value to an internal variable named param. Both of the test methods print their method name along with the param variable value to console when executed.
Let’s run the tests now.
Test method two with param values: 2 Test method two with param values: 1 Test method one with param values: 2 Test method one with param values: 1 PASSED: testMethodTwo PASSED: testMethodTwo PASSED: testMethodOne PASSED: testMethodOne
As you can see from the previous test results both the instances of testMethodTwo
were executed before any instance of testMethodOne
. This is the default behavior of a factory implementation in TestNG, it will execute all the instances of the dependent test methods before the actual test method.
That’s all related to @Factory
annotation in TestNG. Let me know if you have any queries.
Happy Learning !!
Reference:
John Chesshir
“As you can see from the previous test results both the instances of testMethodTwo were executed before any instance of testMethodOne. This is the default behavior of a factory implementation in TestNG, it will execute all the instances of the dependent test methods before the actual test method”
Is there a way to override this “default behavior”?
Polymath Nine
Please go through this question, if you can solve this by factory
https://stackoverflow.com/questions/45239116/how-to-run-multiple-test-cases-in-testng-with-different-set-of-test-data-from-ex
Parth Shah
Nice Article. Can we use multiple @Factory annotation?
So let me give you an example : I want to run run my tests as
-Test 1
>subTest1
-subsubTest1
-subsubTest2
>subTest2
-subsubTest1
-Test2
-Test3
So I used @Factory in first Test then for subTest I again used @Factory but instead of running subsubTest 3 times it ran only twice.
Tharun
Very useful article. “@Factory allows tests to be created at runtime depending on certain data-sets or conditions”. How do I define a specific condition?. For eg: Is it possible to run the above two tests in portrait and landscape screen orientation by defining the orientation in the factory?. The result should be 8 tests in the end (4- portrait and 4-landscape). Currently, I write tests for separate orientation for every single scenario.
Jason
Hi,
Question: Can we use @Factory and @DataProvider where even the test method is having dataProvider, can you give some example?
Gagandeep Sharma
Amazing article. Thanks for such detailed information.
onlinehub12
@Factory
public Object[] factoryMethod()
{
return new Object[] { new DependencyTest(1), new DependencyTest(2) };
}
runs DependencyTest(1) and DependencyTest(2) in parallel, how can i run it sequentially ?