Example of TestNG Factory

0

In this article, I will be showing you an example of TestNG factory.

We use TestNG @Factory to create multiple test instances. The test class may either have the default no-arg constructor or constructor with one or more arguments.

TestNG factory mechanism

In order to understand how a TestNG factory works, we first we need to know how it executes a test method.
In the below class, we run TestNG programmatically.

TestNGRunExample:

package testNGFactory;

import org.testng.TestNG;

import com.javarticles.testng.UITesting;

public class TestNGRunExample {
    public static void main(String[] args) {
        TestNG testng = new TestNG();
        testng.setTestClasses(new Class[] { UITesting.class });
        testng.run();
    }
}

Output:

[TestNG] Running:
  Command line suite

someTest: web
someTest: swing
someTest: JSF

===============================================
Command line suite
Total tests run: 3, Failures: 0, Skips: 0
===============================================

When testing.run() is called, internally, TestNG framework instantiates the classes provided by invoking their no-argument constructor and then proceeds to run all the test methods that can be found on each class.

But what happens if the class doesn’t have a no-argument constructor. In the example below, DummyTestClass has a constructor which takes a param and it doesn’t have a default constructor.

TestNGRunConstructorWithParamExample:

package testNGFactory;

import org.testng.TestNG;

import com.javarticles.testng.DummyTestClass;

public class TestNGRunConstructorWithParamExample {
    public static void main(String[] args) {
        TestNG testng = new TestNG();
        testng.setTestClasses(new Class[] { DummyTestClass.class });
        testng.run();
    }
}
package com.javarticles.testng;

import org.testng.annotations.Test;

public class DummyTestClass {
    private String param;
    public DummyTestClass(String param) {
        this.param = param;
    }
    @Test
    public void dummyTest() {
        System.out.println("Param is " + param);
    }
}

Output:

[TestNG] Running:
  C:\javarticles_ws\testNGFactory\testng.xml

Param is Default test name

===============================================
Suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================

The test case ran fine but since we didn’t provide any argument value, TestNG itself has injected a default value “Default test name”.

Since the class expects a parameter value, we should have a way to create test instances for different values. In order to address this scenario, TestNG provides you with @Factory feature where you can instantiate the test classes yourself. This is done with the @Factory annotation, which must be put on top of a method that returns an array of objects. Each of these objects should be an instance of a class that contains TestNG annotations. The return type of a @Factory method is always Object[].

These objects will also be inspected by TestNG to find out whether they have @Factory annotations as well, in which case the cycle starts again, until TestNG is left with either instances that have no @Factory annotations on them or instances that have @Factory methods that have already been invoked.

TestNG @Factory annotation Example

In this example, test class MultipleFactoryTest has a constructor with parameter param. It contains a @Test method t. It also has a @Factorymethod called create.

In create(), we return an instance of MultipleFactoryTest and TestClass1. TestNG will run the test lifecycle on the returned test instances. The test class TestClass1 itself has a @Factory annotated method create() which returns an instance of TestClass2. Likewise, TestClass2 creates an instance of TestClass3.

When we run MultipleFactoryTest, it ends up running tests of MultipleFactoryTest, TestClass1, TestClass2 and TestClass3.

Though TestNG can create many instances using @Factory,  it guarantees that your @Factory method will be invoked exactly once.

MultipleFactoryTest:

package com.javarticles.testng;

import org.testng.annotations.Factory;
import org.testng.annotations.Test;

public class MultipleFactoryTest {
    private String param;

    public MultipleFactoryTest(String param) {
        this.param = param;
    }

    @Test
    public void t() {
        System.out.println("MultipleFactoryTest:t:" + param);
    }
    
    @Factory
    public Object[] create() {
        return new Object[] { new MultipleFactoryTest("Multiple factory test"), new TestClass1()};
    }
}

TestClass1:

package com.javarticles.testng;

import org.testng.annotations.Factory;
import org.testng.annotations.Test;

public class TestClass1 {
    @Test
    public void t() {
        System.out.println("TestClass1.t");
    }
    
    @Factory
    public Object[] create() {
        return new Object[] { new TestClass2()};
    }
}

TestClass2:

package com.javarticles.testng;

import org.testng.annotations.Factory;
import org.testng.annotations.Test;

public class TestClass2 {
    @Test
    public void t() {
        System.out.println("TestClass2.t");
    }
    
    @Factory
    public Object[] create() {
        return new Object[] { new TestClass3() };
    }
}

TestClass3:

package com.javarticles.testng;

import org.testng.annotations.Test;

public class TestClass3 {
    @Test
    public void t() {
        System.out.println("TestClass3.t");
    }
}

Output:

[TestNG] Running:
  C:\Users\mokkara\AppData\Local\Temp\testng-eclipse-564478107\testng-customsuite.xml

MultipleFactoryTest:t:Multiple factory test
TestClass1.t
TestClass2.t
TestClass3.t
PASSED: t
PASSED: t
PASSED: t
PASSED: t

===============================================
    Default test
    Tests run: 4, Failures: 0, Skips: 0
===============================================


===============================================
Default suite
Total tests run: 4, Failures: 0, Skips: 0

 

Download Eclipse Project

Download the source code here: testNGFactory.zip

Share.

Leave A Reply