A Test Suite is a collection of tests. In our last post Part 2: Scripting using TestNG…, if we check the TestNG results of our ‘FirstTestNScript’ script, we had no control over Test Suite or Test name. By default they are named as ‘Default suite’ and ‘Default test’.
However with the use of testing.xml, not only we can provide names to our test suites and tests but also we can configure our test run, set test dependency, include or exclude any test, method, class or package and set priority etc. In this post we will go through the testng.xml file creation and also some of the ways to configure our ‘FirstTestNScript’ script.
- Right click on our Java Project ‘FrameworkDesign’ and click New -> Other. Below window appears and we need to select XML file inside XML folder. Click Next and name the file as ‘testng.xml‘. Click Finish to close the window.
- Once after completing the above step, we can see that the ‘testing.xml’ file is added to our Java project. There will be two tabs: Design and Source. In the Source tab, copy the below code.
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <!-- Naming our Suite as OurFirstSuite --> <suite name="OurFirstSuite" verbose="1" > <!-- Naming our Test as Functional. We can have as many tests --> < test name="Functional" > <!-- Add TestNG class for execution --> < classes > <!-- Note class name include package name also --> < class name="com.selenium.testcase.FirstTestNScript" /> </classes > </test > </suite >
- If we go through the above code, we provided our suite name as ‘OurFirstSuite’ in the <suite> tag. This is followed by <test name=”Functional”> tag. We can have as many <test> tags but with different name. Inside the <test> tags, <classes> tags are placed. Notice that class name is a combination of package name and TestNG class.
- To execute our TestNG script using ‘testing.xml’, right click on ‘testing.xml’ file and click Run As -> TestNG Suite.
- After successful execution, below results are displayed. Test Suite is now named as ‘OurFirstSuite’ and test is named as ‘Functional’.
- What if we want to run only ‘secondTestCase’ test from our ‘FirstTestNScript’ script? We can configure ‘testng.xml’ to select only required ‘@Test’ methods. In the Source tab, copy the below code.
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <!-- Naming our Suite as OurFirstSuite --> <suite name="OurFirstSuite" verbose="1" > <!-- Naming our Test as Functional. We can have as many tests --> <test name="Functional" > <!-- Add TestNG class for execution --> <classes> <!-- Note class name include package name also --> <class name="com.selenium.testcase.FirstTestNScript"> <!-- Include selective tests --> <methods> <!-- Only Second Test Case will be executed --> <include name="secondTestCase"> </include> </methods> </class> </classes> </test> </suite>
- In the above code we are configuring ‘testing.xml’ to consider only one ‘@Test’ method from our ‘FirstTestNScript’ script. For this we have to use <method> tag followed by <include> tag. However to exclude a particular ‘@Test’ method from our test, we can use <exclude> tag inside <method> tag. After successful execution, below results are displayed. Only the included ‘@Test’ method is executed.
- We can configure ‘testing.xml’ to consider packages instead of classes. This comes in handy when we are doing regression testing. In this case, TestNG will look at all the classes in the package and will retain only classes that have TestNG annotations. In the Source tab, copy the below code and try.
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <!-- Naming our Suite as OurFirstSuite --> <suite name="OurFirstSuite" verbose="1"> <!-- Naming our Test as Functional. We can have as many tests --> <test name="Regression"> <!-- Execute based on packages --> <packages> <!-- Specify package names instead of class names --> <package name="com.selenium.testcase"> </package> </packages> </test> </suite>
- After successful execution, below results are displayed. Notice that there is one more TestNG script named ‘SampleTest’ added to the package ‘com.selenium.testcase’. TestNG executed both files. If we closely analyze the test results, under ‘Regression’ test, there are two TestNG scripts – ‘FirstTestNScript’ and ‘SampleTest’. Inside ‘FirstTestNScript’, ‘secondTestCase’ (1 time) and ‘firstTestCase’ (2 times) are executed. And inside ‘SampleTest’, ‘firstTest’ (2 times) and ‘secondTest’ (2 times) are executed. This is due to Data Provider set up done in ‘FirstTestNScript’ and ‘SampleTest’ is different.
- Using TestNG we can also execute scripts belonging to set of groups. Groups are specified in ‘testng.xml’ file and need to be mentioned inside annotations. However one important point to remember is that groups must be mentioned for all annotations for which ‘@Test’ is dependant. For example in our ‘FirstTestNScript’ script, ‘firstTestCase’ is depending on ‘@BeforeTest’ for setting system properties, ‘@BeforeMethod’ for initializing WebDriver and ‘@AfterMethod’ for closing the WebDriver. Hence groups must be mentioned in all these methods. We will make below changes in our ‘FirstTestNScript’ script.
package com.selenium.testcase; import org.testng.annotations.Test; import org.testng.annotations.BeforeMethod; import org.testng.annotations.AfterMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.BeforeClass; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeTest; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeSuite; import org.testng.annotations.AfterSuite; public class FirstTestNScript { WebDriver driver; @Test(dataProvider = "loginDP", priority=2, groups = "login") public void firstTestCase(String username, String password) { System.out.println("This is our First Test Method"); // Enter username as demo driver.findElement(By.name("userName")).sendKeys(username); // Enter password as demo driver.findElement(By.name("password")).sendKeys(password); // Click Sign in button driver.findElement(By.name("login")).click(); // Assert if Sign Off is displayed after logging in Assert.assertTrue(driver.findElement(By.linkText("SIGN-OFF")).isDisplayed()); System.out.println("First Test Case Passed"); } // Assign WebDriver @BeforeMethod(groups = "login") public void beforeMethod() { System.out.println("This is Before Method"); // Assign WebDriver to ChromeDriver driver = new ChromeDriver(); // Maximize window driver.manage().window().maximize(); // Navigate to New Tours URL driver.get("http://newtours.demoaut.com"); } @AfterMethod(groups = "login") public void afterMethod() { System.out.println("This is After Method"); // Close and quit the driver to close the Browser driver.close(); driver.quit(); } // Setting System Properties @BeforeTest(groups = "login") public void beforeTest() { System.out.println("This is Before Test"); // Setting System properties System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir") + "/Chrome/chromedriver"); } }
- And we will update the ‘testng.xml’ file with below code.
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <!-- Naming our Suite as OurFirstSuite --> <suite name="OurFirstSuite" verbose="1"> <!-- Naming our Test as Functional. We can have as many tests --> <test name="Functional"> <!-- Include required groups to execute --> <groups> <!-- group = login --> <run> <include name="login" /> </run> </groups> <!-- Include classes where groups are mentioned --> <classes> <class name="com.selenium.testcase.FirstTestNScript" /> </classes> </test> </suite>
- After successful execution, below results are displayed. Notice that only ‘firstTestCase’ is executed inside ‘FirstTestNScript’ script as it placed under ‘login’ groups.
- We have learned passing parameters using Data Provider. There is another way of passing parameters and that is through ‘testing.xml’. The parameter values can be set at both suite and test level in the testng XML file and based on scope, parameters can be used in the TestNG script. However any parameter value defined at the test level will override the value of a parameter, with same name, if defined at suite level. We will make following changes in our ‘firstTestCase’ code. Notice that we removed Data Provider from our ‘firstTestCase’ code and used ‘@Parameters’ instead. No other changes to ‘FirstTestNScript’ class.
@Test(groups = "login") @Parameters({"username","password"}) public void firstTestCase(String username, String password) { System.out.println("This is our First Test Method"); // Enter username as demo driver.findElement(By.name("userName")).sendKeys(username); // Enter password as demo driver.findElement(By.name("password")).sendKeys(password); // Click Sign in button driver.findElement(By.name("login")).click(); // Assert if Sign Off is displayed after logging in Assert.assertTrue(driver.findElement(By.linkText("SIGN-OFF")).isDisplayed()); System.out.println("First Test Case Passed"); }
- If we add parameters at suite level, then they are accessible to all the methods. In below example parameters ‘username’ and ‘password’ are accessible to all methods in TestNG script using ‘@Parameters’ annotation.
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <!-- Naming our Suite as OurFirstSuite --> <suite name="OurFirstSuite" verbose="1"> <!-- Adding parameters at suite level --> <parameter name="username" value="demo"></parameter> <parameter name="password" value="demo"></parameter> <!-- Naming our Test as Functional. We can have as many tests --> <test name="Functional"> <!-- Include required groups to execute --> <groups> <!-- group = login --> <run> <include name="login" /> </run> </groups> <!-- Include classes where groups are mentioned --> <classes> <class name="com.selenium.testcase.FirstTestNScript" /> </classes> </test> </suite>
- If we add parameters at test level, then they are accessible to only those methods that are in scope of test. In below example parameters ‘username’ and ‘password’ are accessible to only those methods that are in scope of <test name=”Functional”>.
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <!-- Naming our Suite as OurFirstSuite --> <suite name="OurFirstSuite" verbose="1"> <!-- Naming our Test as Functional. We can have as many tests --> <test name="Functional"> <!-- Adding parameters at test level --> <parameter name="username" value="demo"></parameter> <parameter name="password" value="demo"></parameter> <!-- Include required groups to execute --> <groups> <!-- group = login --> <run> <include name="login" /> </run> </groups> <!-- Include classes where groups are mentioned --> <classes> <class name="com.selenium.testcase.FirstTestNScript" /> </classes> </test> </suite>
- TestNG also allow us to send Optional parameters. If we don’t mention parameters in ‘testing.xml’ then there is way to pass parameters to test method using ‘@Optional‘ annotation. In below example, TestNG uses the parameters passed from ‘@Optional‘ for the ‘firstTestCase’. This happened because TestNG was unable to find parameters named ‘username’ and ‘password’ in the ‘testing.xml’ file.
@Test(groups = "login") @Parameters({"username","password"}) public void firstTestCase(@Optional("demo") String username, @Optional("demo") String password) { System.out.println("This is our First Test Method"); // Enter username as demo driver.findElement(By.name("userName")).sendKeys(username); // Enter password as demo driver.findElement(By.name("password")).sendKeys(password); // Click Sign in button driver.findElement(By.name("login")).click(); // Assert if Sign Off is displayed after logging in Assert.assertTrue(driver.findElement(By.linkText("SIGN-OFF")).isDisplayed()); System.out.println("First Test Case Passed"); }
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <!-- Naming our Suite as OurFirstSuite --> <suite name="OurFirstSuite" verbose="1"> <!-- Naming our Test as Functional. We can have as many tests --> <test name="Functional"> <!-- Include required groups to execute --> <groups> <!-- group = login --> <run> <include name="login" /> </run> </groups> <!-- Include classes where groups are mentioned --> <classes> <class name="com.selenium.testcase.FirstTestNScript" /> </classes> </test> </suite>
- There is one more way of passing parameters from ‘testing.xml’ and that is by using ‘org.testng.ITestContext’. In the ‘testing.xml’ file, we will pass parameters for url and ‘Chrome Driver location.
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <!-- Naming our Suite as OurFirstSuite --> <suite name="OurFirstSuite" verbose="1"> <!-- Passing url and chrome driver location --> <parameter name="url" value="http://newtours.demoaut.com"></parameter> <parameter name="chromeDriver" value="/Chrome/chromedriver"></parameter> <!-- Naming our Test as Functional. We can have as many tests --> <test name="Functional"> <!-- Adding parameters at test level --> <parameter name="username" value="demo"></parameter> <parameter name="password" value="demo"></parameter> <!-- Include required groups to execute --> <groups> <!-- group = login --> <run> <include name="login" /> </run> </groups> <!-- Include classes where groups are mentioned --> <classes> <class name="com.selenium.testcase.FirstTestNScript" /> </classes> </test> </suite>
- We will make below changes to our ‘FirstTestNScript’ script. We will use ITestContext to pass data from ‘testng.xml’ file to our script. Notice that we removed unwanted methods from our ‘FirstTestNScript’ script.
package com.selenium.testcase; import org.testng.annotations.Test; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeTest; import org.testng.annotations.AfterMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Parameters; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.testng.Assert; import org.testng.ITestContext; public class FirstTestNScript { WebDriver driver; String url; String chromeDriverLocation; @Test(groups = "login") @Parameters({"username","password"}) public void firstTestCase(String username, String password) { System.out.println("This is our First Test Method"); // Enter username as demo driver.findElement(By.name("userName")).sendKeys(username); // Enter password as demo driver.findElement(By.name("password")).sendKeys(password); // Click Sign in button driver.findElement(By.name("login")).click(); // Assert if Sign Off is displayed after logging in Assert.assertTrue(driver.findElement(By.linkText("SIGN-OFF")).isDisplayed()); System.out.println("First Test Case Passed"); } @Test(dataProvider = "registerDP", priority=1) public void secondTestCase(String fname, String lname, String username, String pwd, String cpwd) { System.out.println("This is Second Test Method"); // Click Register link in Home page driver.findElement(By.linkText("REGISTER")).click(); // Enter first name as fname driver.findElement(By.name("firstName")).sendKeys(fname); // Enter last name as lname driver.findElement(By.name("lastName")).sendKeys(lname); // Enter username as user driver.findElement(By.name("email")).sendKeys(username); // Enter password as pwd driver.findElement(By.name("password")).sendKeys(pwd); // Enter confirm password as cpwd driver.findElement(By.name("confirmPassword")).sendKeys(cpwd); // Click Submit to complete registration process driver.findElement(By.name("register")).click(); System.out.println("Second Test Case Passed"); } // Assign WebDriver @BeforeMethod(groups = "login") public void beforeMethod(ITestContext context) { System.out.println("This is Before Method"); url = context.getCurrentXmlTest().getParameter("url"); // Assign WebDriver to ChromeDriver driver = new ChromeDriver(); // Maximize window driver.manage().window().maximize(); // Navigate to New Tours URL driver.get(url); } @AfterMethod(groups = "login") public void afterMethod() { System.out.println("This is After Method"); // Close and quit the driver to close the Browser driver.close(); driver.quit(); } // DataProvider method for login data @DataProvider public Object[][] loginDP() { // username = demo, passowrd = demo return new Object[][] { { "demo", "demo" }, { "demo", "demo" } }; } // DataProvider method for registering @DataProvider public Object[][] registerDP() { // first name = fname, last name = lname, username = user, password = // pwd, confirm password = pwd return new Object[][] { { "fname", "lname", "user", "pwd", "pwd" } }; } // Setting System Properties @BeforeTest(groups = "login") public void beforeTest(ITestContext context) { System.out.println("This is Before Test"); chromeDriverLocation = context.getCurrentXmlTest().getParameter("chromeDriver"); // Setting System properties System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir") + chromeDriverLocation); } }
- In the above code, we are using ITestContext object to pass parameters from ‘testng.xml’ file to our script. We declared two String variables ‘url’ and ‘chromeDriverLocation’ and later assigning the values in ‘@BeforeTest’ and ‘@BeforeMethod’ methods. After successful execution, below results are displayed. Notice that all parameters are passed correctly from ‘testng.xml’ file and only ‘firstTestCase’ is executed.
With this we came to an end of TestNG tutorial. The topic is huge and it requires a constant practice to master it. Hope you were able to follow most of it.
Happy Learning!