TestNG beforeSuite Example
In this article, we will show you how to use the TestNG @BeforeSuite
annotation.
If you have used JUnit annotations, you will be familiar with @BeforeClass
. In TestNG, apart from @BeforeClass
, we also have additional annotations like @BeforeTest
and @BeforeSuite
.
@BeforeSuite
will be executed before any tests declared inside a TestNG suite are run.
So how is it different from the @BeforeClass
annotation? Well… The differences will get clear in a moment as we go through the examples, but first a bit about the setup details:
- I am using Eclipse as the IDE, version Luna 4.4.1.
- I will be running the tests using eclipse TestNG plugin so you need to install the TestNG Eclipse Plugin.
1. Example of @BeforeSuite
In order to know when a @BeforeSuite
method gets called, we first need to know what a suite is and how it is defined.
A suite is defined by one or more tests and is represented by one XML file which the TestNG will use to run the tests. The XML file will define the set of tests to be run. It is represented by the <suite>
tag and it is the first tag that appears in the XML file.
Lets call this file testng.xml
.
Each element of the structure defines an event in TestNG lifecycle and is represented by an annotation. Every time a method is annotated with one of these, it will run in the event that the annotation represents.
The testng.xml
contains the following structure:
- First element is called
suite
- A
suite
contains one or moretest
elements. - A
test
element is made up of one or more classes - Finally, a class contains one or more test methods
A @BeforeSuite
annotated method represents an event before the suite starts, so all the @BeforeSuite
methods will be executed before the first test declared within the test
element is invoked.
Let’s understand this through an example. Below is the configuration test file that the example uses. The suite contains two tests Test1
and Test2
. Test1
contains test class TestClass1
and Test2
contains test class TestClass2
.
testng.xml:
<?xml version="1.0" encoding="UTF-8"?> <suite name="Suite" parallel="false"> <test name="Test1"> <classes> <class name="com.javacodegeeks.testng.TestClass1" /> </classes> </test> <test name="Test2"> <classes> <class name="com.javacodegeeks.testng.TestClass2" /> </classes> </test> </suite>
In TestClass1
, we have one @BeforeSuite
method called suiteSetup1
at suite
level and there are other @Before
and @After
annotated methods at test
, class
and method
level. We also have couple of @Test
methods.
TestClass1:
package com.javacodegeeks.testng; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; public class TestClass1 { @BeforeSuite public void suiteSetup1() { System.out.println("testClass1.suiteSetup1: before suite"); } @BeforeTest public void beforeTest() { System.out.println("testClass1: before test"); } @Test public void unitLevel1() { System.out.println("testClass1: Unit level1 testing"); } @Test public void unitLevel2() { System.out.println("testClass1: Unit level2 testing"); } @BeforeMethod public void beforeMethod() { System.out.println("testClass1: before method"); } @AfterMethod public void afterMethod() { System.out.println("testClass1: after method"); } @BeforeClass public void beforeClass() { System.out.println("testClass1: before class"); } @AfterClass public void afterClass() { System.out.println("testClass1: after class"); } @AfterSuite public void cleanupSuite() { System.out.println("testClass1.cleanupSuite: after suite"); } }
In TestClass2
, we have one @BeforeSuite
method called suiteSetup2
at suite
level and a @Test
method. The rest of the methods are @Before
annotated methods at test
, class
and method
level.
TestClass2:
package com.javacodegeeks.testng; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; public class TestClass2 { @BeforeSuite public void suiteSetup2() { System.out.println("testClass2.suiteSetup2: before suite"); } @BeforeTest public void beforeTest() { System.out.println("testClass2: before test"); } @BeforeClass public void beforeClass() { System.out.println("testClass2: before class"); } @BeforeMethod public void beforeMethod() { System.out.println("testClass2: before method"); } @Test public void unitLevel() { System.out.println("testClass2: Unit level testing"); } }
When we run testng.xml
, we see the order in which the annotated methods are fired. The very first methods that run are the @BeforeSuite
methods. Since each of the test classes have one @BeforeSuite
, both are consecutively run and then only other annotated methods are fired starting with @BeforeTest
method.
Output:
[TestNG] Running: C:\javacodegeeks_ws\testNgBeforeSuite\test\com\javacodegeeks\testng\testng.xml testClass1.suiteSetup1: before suite testClass2.suiteSetup2: before suite testClass1: before test testClass1: before class testClass1: before method testClass1: Unit level1 testing testClass1: after method testClass1: before method testClass1: Unit level2 testing testClass1: after method testClass1: after class testClass2: before tst testClass2: before class testClass2: before method testClass2: Unit level testing testClass1.cleanupSuite: after suite =============================================== Suite Total tests run: 3, Failures: 0, Skips: 0 ===============================================
2. Example of parent and child suites
In this example, we have a parent suite that contains child suites. Each child suite has one test class and each test class has one @BeforeSuite
method. The parent suite contains a common parameter called param
which the @BeforeSuite
methods of the child suites share.
parentSuite.xml
<?xml version="1.0" encoding="UTF-8"?> <suite name="Parent Suite"> <parameter name="param" value="SuiteExample"></parameter> <suite-files> <suite-file path="./childSuite1.xml"/> <suite-file path="./childSuite2.xml"/> </suite-files> </suite>
childSuite1.xml:
<?xml version="1.0" encoding="UTF-8"?> <suite name="Child Suite1"> <test name="Test"> <classes> <class name="com.javacodegeeks.testng.ChildTestClass1"/> </classes> </test> </suite>
childSuite2.xml:
<?xml version="1.0" encoding="UTF-8"?> <suite name="Child Suite2"> <test name="Test"> <classes> <class name="com.javacodegeeks.testng.ChildTestClass2"/> </classes> </test> </suite>
ChildTestClass1
and ChildTestClass2
each has a @BeforeSuite
method that takes in a parameter whose value is set in the parent suite.
ChildTestClass1:
package com.javacodegeeks.testng; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Parameters; public class ChildTestClass1 { @BeforeSuite @Parameters("param") public void beforeSuite(String p) { System.out.println("ChildTestClass1: before suite " + p); } }
In each @BeforeSuite
method, we print the parameter value.
ChildTestClass2:
package com.javacodegeeks.testng; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Parameters; public class ChildTestClass2 { @BeforeSuite @Parameters("param") public void beforeSuite(String p) { System.out.println("ChildTestClass2: before suite " + p); } }
When you run the parent suite, you can see that the parameter value set at parent suite is received by both the child suites.
Output:
[TestNG] Running: C:\javacodegeeks_ws\testNgBeforeSuite\test\com\javacodegeeks\testng\childSuite1.xml ChildTestClass1: before suite SuiteExample =============================================== Child Suite1 Total tests run: 0, Failures: 0, Skips: 0 =============================================== [TestNG] Running: C:\javacodegeeks_ws\testNgBeforeSuite\test\com\javacodegeeks\testng\childSuite2.xml ChildTestClass2: before suite SuiteExample =============================================== Child Suite2 Total tests run: 0, Failures: 0, Skips: 0 =============================================== [TestNG] Running: C:\javacodegeeks_ws\testNgBeforeSuite\test\com\javacodegeeks\testng\parentSuite.xml =============================================== Parent Suite Total tests run: 0, Failures: 0, Skips: 0 ===============================================
3. @BeforeSuite with ITestContext parameter
A @BeforeSuite
method can be declared with a parameter of type ITestContext
. In the below example, class ContextBeforeSuite
has one such @BeforeSuite
method.
contextSuite.xml:
<?xml version="1.0" encoding="UTF-8"?> <suite name="Context Suite"> <test name="Test"> <classes> <class name="com.javacodegeeks.testng.ContextBeforeSuite" /> </classes> </test> </suite>
ContextBeforeSuite:
Using the context
, we print the suite name.
package com.javacodegeeks.testng; import org.testng.ITestContext; import org.testng.annotations.BeforeSuite; public class ContextBeforeSuite { @BeforeSuite public void beforeSuite(ITestContext context) { System.out.println("ContextBeforeSuite: before suite " + context.getSuite().getName()); } }
Output:
[TestNG] Running: C:\javacodegeeks_ws\testNgBeforeSuite\test\com\javacodegeeks\testng\contextSuite.xml ContextBeforeSuite: before suite Context Suite =============================================== Context Suite Total tests run: 0, Failures: 0, Skips: 0 Configuration Failures: 1, Skips: 0 ===============================================
4. @BeforeSuite behavior when used in Factory
@BeforeSuite
methods shouldn’t run more than once even when used in Factory
.
TestClassFactory
below defines a factory method createTestClass
. This factory method returns an array of two objects of TestClass
class.
TestClassFactory:
package com.javacodegeeks.testng; import org.testng.annotations.Factory; public class TestClassFactory { @Factory public Object[] createTestClass() { return new Object[]{new TestClass("1"), new TestClass("2")}; } }
TestClass
contains a dummy test which prints the param passed in while creating TestClass
object. It has a @BeforeSuite
method which we are expecting will be invoked only once even if the test is driven by the factory.
TestClass:
package com.javacodegeeks.testng; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; public class TestClass { private String param; public TestClass(String param) { this.param = param; } @BeforeSuite public void beforeSuite() { System.out.println("before suite"); } @Test public void dummyTest() { System.out.println("dummy test " + param); } }
Select the factory class in eclipse and run it as TestNG test. Note that the @BeforeSuite
method fires only once.
Output:
[TestNG] Running: C:\Users\mokkara\AppData\Local\Temp\testng-eclipse-50136982\testng-customsuite.xml before suite dummy test 2 dummy test 1 PASSED: dummyTest PASSED: dummyTest =============================================== Default test Tests run: 2, Failures: 0, Skips: 0 =============================================== =============================================== Default suite Total tests run: 2, Failures: 0, Skips: 0 ===============================================
5. @BeforeSuite with dependency method
When a test suite has multiple @BeforeSuite
methods and we want them to be invoked in a particular order, then we use the dependsOnMethods
attribute to add the dependent methods.
beforeSuiteWithDependency.xml:
<?xml version="1.0" encoding="UTF-8"?> <suite name="Suite"> <test name="Test Before Suite Dependency"> <classes> <class name="com.javacodegeeks.testng.BeforeSuiteDependency" /> </classes> </test> </suite>
The @BeforeSuite
method secondBeforeSuite
depends on firstBeforeSuite
and beforeSuite
methods so it is called only after the dependent methods are called.
BeforeSuiteDependency:
package com.javacodegeeks.testng; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; public class BeforeSuiteDependency { @BeforeSuite(dependsOnMethods={"firstBeforeSuite","beforeSuite"}) public void secondBeforeSuite() { System.out.println("Second Before suite"); } @BeforeSuite public void firstBeforeSuite() { System.out.println("First before suite"); } @BeforeSuite public void beforeSuite() { System.out.println("before suite"); } @Test public void unitTest() { System.out.println("Unit test"); } }
Output:
[TestNG] Running: C:\javacodegeeks_ws\testNgBeforeSuite\test\com\javacodegeeks\testng\beforeSuiteWithDependency.xml before suite First before suite Second Before suite Unit test =============================================== Suite Total tests run: 1, Failures: 0, Skips: 0 ===============================================
Download the Eclipse Project
In this article we have provided several examples of the TestNG @BeforeSuite.
You can download the full source code of this example here: testNgBeforeSuite.zip
In 2. Example of parent and child suites, is it possible to call BeforeSuite only once?
Thank you for the solution😊