TestNG @Factory with Examples

Learn about the TestNG @Factory annotation that allows the tests to be created at runtime depending on provided datasets or conditions.

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 scenarios. The problem with this approach is that if we get an extra set of data, we will need to add more tests.

TestNG solves this problem by providing the @Factory annotation feature. @Factory defines and creates tests dynamically at runtime.

Factories allow us to create tests dynamically.

A @Factory method returns objects that will be used by TestNG as Test classes. TestNG will scan for test methods in these classes and run those tests.

The factory method can receive parameters just like @Test. We can also add @Before/@After methods. It is mandatory that a factory method should return an array of Object i.e. Object [].

See Also: TestNG @DataProvider

2. @Factory Syntax

Let’s create a test using the @Factory annotation to understand how to use the 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 we 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 factory 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. @Factory with Parameters

One of the main advantages of using the factory methods is that we can pass parameters to test classes while initializing them. These parameters can then be used across all the test methods present in the said test 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 constructor argument is used in the test methods present in the test class.

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 is executed two times. The parameters passed while initializing the test class are used by the test methods and the console shows the respective output.

See Also: TestNG @Parameters

4. Combining @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.

@Factory 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

See Also: TestNG – @Factory vs @DataProvider

5. Dependent Tests with @Factory

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) };
	}
}

Above 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 we 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.

Happy Learning !!

Sourcecode on Github

Comments

Subscribe
Notify of
guest
6 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode