Test Automation with TestNG using Page Object Modeling

In software development, product objectives must be tested and validated in order to ensure the reliability and the productivity of the design process. For the above purpose, a test automation framework is needed to assure the maintainability and the re-usability of the test cases written, because test automation should be accomplished in a manner where it should be able to cope with any further changes made on the web application or the UI which we are testing. Therefore testNG and POM(Page Object Modeling) are supportive tools for the test automation.

Why testNG ?

TestNG is a test automation framework for java, developed to overcome the limitations of JUnit and NUnit. TestNG covers the test categories such as unit-testing, functional-testing, integration-testing and end-to-end testing. TestNG accommodates features and advantages given below.

Requirements

Before moving further, you need to do the following.

  1. Create a maven project using IntelliJ or Eclipse IDE.
  2. Add testNG plugin as a maven dependency in pom.xml file. (Following code-snippet should be added in between “dependencies” tags in pom.xml and change the version of the plugin as your preference.)
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>

Features and Advantages

  • TestNG provides much more flexibility over any test automation tools because of its ability to render grouping tests and dependency tests. As an example, you can assign your test cases into 2 different groups and each group can be invoked by passing its group name.

Create a test class namely “LoadingTest” in test folder in your maven project and add the following test methods with the group attribute in @Test annotation as given.

import org.testng.annotations.Test;

public class LoadingTest {

@Test(groups = {"inventory_loading"})
public void validateLoadingTest(){
System.out.println("test passed inventory_loading group");
}

@Test(groups = {"inventory_picking"})
public void validatePickingTest(){
System.out.println("test passed inventory_picking group");
}
}

Create another XML file with the following code-snippet (suite name and test name can be as your preference).

<suite name="businessTestSuite">
<test name="testngTest">
<groups>
<run>
<include name="inventory_loading" />
</run>
</groups>
<classes>
<class name = "LoadingTest" />
</classes>
</test>
</suite>

Now you can run the XML file and observe that only the test methods in the “inventory_loading” group will be implemented.Verify the output whether only validateLoadingTest is executed as follows.

test passed inventory_loading group===============================================
businessTestSuite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
Process finished with exit code 0
  • Unlike Junit, parallel execution of test cases is possible with testNG. In the following example, you can observe how it can be implemented.

Change the XML file we created as follows.

<suite name="businessTestSuite" parallel="methods" thread-count="2">
<test name="testngTest">
<classes>
<class name="LoadingTest"/>
</classes>
</test>
</suite>

Here you can see in suite tag we have given 2 attributes namely parallel (to pass the “methods” in which only the methods will be executed simultaneously) and thread-count (to pass the number of maximum threads to be created).

Now change the LoadingTest class as follows to verify the test methods run in different threads.

Now run the XML file and observe the output as follows.

Validate Picking Test Thread ID:- 11Validate Loading Test Thread ID:- 10===============================================
businessTestSuite
Total tests run: 2, Failures: 0, Skips: 0
===============================================
Process finished with exit code 0
  • Test reports can also be generated using testNG in XML or HTML format.

In Eclipse IDE test reports will be automatically generated and you can open them with web browser, but in IntelliJ IDE you have to do the following to generate the test reports.

Install Create TestNG XML.(file > settings > plugins > Create TestNG XML).

Go to the menu Run > Edit Configuration > Listener and add the EmailableReporter and FailedReporter Listener Classes as shown below.

Now run your LoadingTest class and you will see emailable-report.html (for passed test cases ) and testng-failed.xml file (for failed test cases) in test-output folder as follows.

Now right click on the mentioned html file and click on open in browser to select on which browser you want to open it.

Now the output will be visible as follows on the selected browser.

  • Annotations are not mandatory in testNG. (@BeforeClass or @AfterClass can be invoked as your preferance)
  • TestNG contains a wide range of SetUp/Teardown annotations such as @Before/AfterSuite, @Before/AfterTest and @Before/AfterGroup.
  • TestNG annotations provide a wide variety of attributes such as description (a brief explanation for the written test case can be given), priority (each test case can be prioritized in which order they are going to be implemented), dependsOnMethods (dependent method will run only if the methods on which it depends on are passed), enabled (By default its value is true, to skip the test enabled = false can be added as an attribute to the @Test annotation), groups(test cases can be grouped on their differences in the functionality as shown in first example) etc.
  • Asserts in testNG helps to validate the condition of the test: success or failure. Assertion with assertEqual(actual,expected), assertNotSame(actual,expected) checks whether actual and the expected values are the same. For condition checking whether true or false; assertTrue(condition), assertFalse(condition) can be used.

Following example will briefly show how the attributes of the testNG annotations help us to make the test automation much easier.

Change the LoadingTest class as follows and run it.

import org.testng.Assert;
import org.testng.annotations.Test;

public class LoadingTest {

@Test (description = "arrival of the load related activites")
public void validateLoadArriveTest(){
System.out.println("Validate Load Arrive Test");
}

@Test (dependsOnMethods = {"validateLoadArriveTest"})
public void validateLoadingTest(){
System.out.println("Validate Loading Test");
Assert.assertTrue(false);
}

@Test (dependsOnMethods = {"validateLoadingTest"})
public void validateLoadDepartureTest(){
System.out.println("Validate Load Departure Test");
}

@Test (enabled = false)
public void validatePickingTest(){
System.out.println("Validate Picking Test");
}
}

Here you can see, for the validateLoadArriveTest method, we have added a description to briefly explain it and validateLoadingTest depends on its success/failure due to the added dependsOnMethods attribute in @Test.

Now run the LoadingTest class and observe the output as follows in the console.

Now you can see validateLoadingTest failed due to the assertion failure as you can see in the code above. As a result validateLoadDepartureTest will be ignored due to its dependency on validateLoadingTest. ValidatePickingTest won’t be executed due to its enabled attribute which is given as false.

Why POM ?

With the new technological advancement, any software company should adopt to modern technologies to keep up with the modern world. Therefore it is essential to do relevant changes in the web application or the UI currently launched in the market. Therefore the test framework should be designed to minimize the impact due to the changes in the web application or the UI. POM will be supportive on that purpose.

For that, a couple of layers in the framework should be created where actions related to UI attributes or the web elements will be maintained only in the “Page” class (There should be a designated “Page” class for each page/form in the application). Test logic will be written in “Function” classes which invokes the actual page actions in the page class where “Test” classes are to call functions in the “Function” class maintaining the business logic. It is supposed to prevent tight coupling in test logic from the UI layer to allow any changes in application with minimum effect on test automation.

Here you can see the LoadingPage class can be used to invoke the relevent web element actions in your UI or web application.

All the buisness logic needs for the LoadingTest can be written in LoadingFunction class and as a result tight coupling between LoadingTest and LoadingPage classes can be removed.

Finally…

TestNG will be a greatly supportive tool for the test automation with the advanced features mentioned above with the examples. In addition, it is a good practice to work on your automation with the help of POM to reduce the effort you need to waste on making changes to your test framework if any changes made on the application on which you are testing.

So it will be a happy ending for your test automation at the end…!

Undergraduate of Electronic and Telecommunication dept. University of Moratuwa, Sri Lanka