Appium Organizing Multiple Test Scenarios in Appium Using TestNG Estimated reading: 18 minutes 195 views In the dynamic world of mobile application testing, managing and organizing multiple test scenarios efficiently is crucial for ensuring robust and reliable testing. Appium, combined with TestNG, provides a powerful framework to achieve this. This guide will walk you through the process of organizing multiple test scenarios in Appium using TestNG, leveraging the power of Java. Whether you’re a beginner or an advanced user, this comprehensive guide will help you streamline your test automation process and enhance your testing capabilities. We will be using the project we setup previously. Setting Up Maven ProjectLet’s navigate to the pom.xml file so we can add the TestNG dependency. We’ll be using TestNG version 7.1.0 for our project. Adding TestNG Dependency To pom.xmlTestNG Dependency (pom.xml)<dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>7.1.0</version> <scope>compile</scope> </dependency>By adding the TestNG dependency to your Maven project, you now have the necessary annotations to write and execute TestNG tests within the Appium project.Creating TestNG Class Let’s head back to our directory /src/test/java/com/test/ where we’ll create a copy of the existing FirstAppiumTest class. We’ll then rename this copy to FirstAppiumTestNG to begin restructuring the test to support TestNG. This new class will serve as our foundation for integrating TestNG functionalities. Copying FirstAppiumTest Class Pasting FirstAppiumTest Class Rename Copied File to FirstAppiumTestNGImporting TestNG AnnotationsIn the newly created FirstAppiumTestNG class, begin by importing the necessary TestNG annotations. These will include @BeforeClass, @AfterClass, and @Test.FirstAppiumTestNG.classimport org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; The @BeforeClass annotation will be used to set up the Appium driver before any tests are run, ensuring that the environment is correctly initialized. Similarly, the @AfterClass annotation will handle the teardown process, cleaning up resources once all tests have been executed. The @Test annotation will be applied to individual test methods, marking them as TestNG test cases.Modifying Class To Support TestNGSo what we’re going to do is remove the main() function call and close the curly bracket from our initial setup. Next, we will create a new public static AndroidDriver variable called driver. BeforeClassIn the @BeforeClass method, we will move the Desired Capabilities setup into the setup() function. This approach ensures that our Appium driver is properly configured before any tests are execute. Moving Desired Capabilities To BeforeClass MethodTest MethodIn the @Test method, we will add our simple test case from the previous guide, which is to click the Add Task button. This test will validate that our application responds correctly when adding a new task. By organizing our tests this way, we maintain a clear separation of concerns, making our test cases easier to manage and understand. Moving Scenario To Test MethodAfterClass MethodFinally, we’ll move the driver.quit() function into the @AfterClass teardown method. This adjustment ensures that the Appium driver is properly closed after all tests have been executed, cleaning up any resources used during the test run. Moving The Closing of the Driver in AfterClass MethodFirstAppiumTestNG.class (w/ Before & After Methods)package com.test; import io.appium.java_client.android.AndroidDriver; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class FirstAppiumTestNG { public static AndroidDriver driver; @BeforeClass public void setUp() throws MalformedURLException { File app = new File("src/test/resources/app/app-debug.apk"); // Set the desired capabilities for your test DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("deviceName", "emulator-5554"); caps.setCapability("platformName", "android"); caps.setCapability("app",app.getAbsolutePath()); // Initialize the Appium driver driver = new AndroidDriver (new URL("http://127.0.0.1:4273/wd/hub"), caps); } @Test public void clickingAddTaskButton() throws InterruptedException { // Add test case scenario here WebElement addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab")); addTaskButton.click(); // quick debug wait for 1 seconds Thread.sleep(1000); System.out.println("TEST PASSED!"); } @AfterClass public void tearDown() { if (driver != null) { // Close the driver session driver.quit(); } } }Adding More Test & AssertionsWhy stop here? Next, we’ll add some assertions and create two more test scenarios to highlight the beauty of TestNG running multiple scenarios and validating our expectations. We will create new tests called addingTaskToDoTheList() and deletingTaskFromTheList(), similar to the test we created using Espresso in our Android guides. We will add these methods to our file, and then we should be ready to run our tests.In our first new test scenario, we focus on adding a task to our to-do list. This test begins by clicking the “Add Task” button to navigate to the task addition screen. We verify that the user is on the correct screen by checking the presence of the title input field. Here’s how the implementation looks:Test: clickingAddTaskButton()@Test public void clickingAddTaskButton() throws InterruptedException { // Add test case scenario here WebElement addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab")); addTaskButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); WebElement addTaskTitle = driver.findElement(By.id("com.example.todoapp:id/titleEditText")); Assert.assertTrue(addTaskTitle.isDisplayed(), "User is on the Add Task Details Screen"); driver.navigate().back(); Thread.sleep(1000); }addingTaskToDoTheList() TestNext, we have the addingTaskToDoTheList() method, which adds a task to the to-do list. This method clicks the “Add Task” button, enters a title and description for the new task, and then saves it. After saving, it verifies that the new task appears in the task list.Test: addingTaskToDoTheList()@Test public void addingTaskToDoTheList() throws InterruptedException { WebElement addTaskButton, saveButton; WebElement addTaskTitleField, addTaskDescField; // click the Add Task button addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab")); addTaskButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); // add title to the task addTaskTitleField = driver.findElement(By.id("com.example.todoapp:id/titleEditText")); addTaskTitleField.click(); addTaskTitleField.sendKeys("Buy Milk"); // add description to the task addTaskDescField = driver.findElement(By.id("com.example.todoapp:id/descriptionEditText")); addTaskDescField.click(); addTaskDescField.sendKeys("Grab 2 Gallons of Milk"); // click the Save button saveButton = driver.findElement(By.id("com.example.todoapp:id/saveButton")); saveButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); WebElement newTaskAdded = driver.findElement(By.id("com.example.todoapp:id/textView")); Assert.assertEquals(newTaskAdded.getText().toString(), "Buy Milk", "New Task Found"); }deletingTaskFromTheList() TestFinally, we have the deletingTaskFromTheList() method, which tests the deletion of a task from the list. This method locates the delete button and clicks it, then verifies that the task is removed from the task list.Test: deletingTaskFromTheList()@Test public void deletingTaskFromTheList() throws InterruptedException { WebElement deleteButton; // click the Delete button deleteButton = driver.findElement(By.id("com.example.todoapp:id/doneButton")); deleteButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); Assert.assertTrue(true, "Task is deleted & is removed from the Task List Screen"); }Full ImplementationHere’s the full implementation of the FirstAppiumTestNG file. FirstAppiumTestNG - Full ImplementationFirstAppiumTestNG.classpackage com.test; import io.appium.java_client.android.AndroidDriver; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class FirstAppiumTestNG { public static AndroidDriver driver; @BeforeClass public void setUp() throws MalformedURLException { File app = new File("src/test/resources/app/app-debug.apk"); // Set the desired capabilities for your test DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("deviceName", "emulator-5554"); caps.setCapability("platformName", "android"); caps.setCapability("app",app.getAbsolutePath()); // Initialize the Appium driver driver = new AndroidDriver (new URL("http://127.0.0.1:4273/wd/hub"), caps); } @Test public void clickingAddTaskButton() throws InterruptedException { // Add test case scenario here WebElement addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab")); addTaskButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); WebElement addTaskTitle = driver.findElement(By.id("com.example.todoapp:id/titleEditText")); Assert.assertTrue(addTaskTitle.isDisplayed(), "User is on the Add Task Details Screen"); driver.navigate().back(); Thread.sleep(1000); } @Test public void addingTaskToDoTheList() throws InterruptedException { WebElement addTaskButton,saveButton; WebElement addTaskTitleField,addTaskDescField; // click the Add Task button addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab")); addTaskButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); // add title to the task addTaskTitleField = driver.findElement(By.id("com.example.todoapp:id/titleEditText")); addTaskTitleField.click(); addTaskTitleField.sendKeys("Buy Milk"); // add description to the task addTaskDescField = driver.findElement(By.id("com.example.todoapp:id/descriptionEditText")); addTaskDescField.click(); addTaskDescField.sendKeys("Grab 2 Gallons of Milk"); // click the Save button saveButton = driver.findElement(By.id("com.example.todoapp:id/saveButton")); saveButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); WebElement newTaskAdded = driver.findElement(By.id("com.example.todoapp:id/textView")); Assert.assertEquals(newTaskAdded.getText().toString(), "Buy Milk", "New Task Found"); } @Test public void deletingTaskFromTheList() throws InterruptedException { WebElement deleteButton; // click the Delete button deleteButton = driver.findElement(By.id("com.example.todoapp:id/doneButton")); deleteButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); Assert.assertTrue(true, "Task is deleted & is removed from the Task List Screen"); } @AfterClass public void tearDown() { if (driver != null) { // Close the driver session driver.quit(); } } }Running Test: TestNG XML File SetupNow that we’re ready to run our test, let’s create a new testng.xml file in the root of our project. In this new file, we’ll add the XML code below to enable running our FirstAppiumTestNG class.TestNG Suite Config (testng.xml)<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="My First Appium TestNG Test"> <test name="TODO App Automation Testing"> <classes> <class name="com.test.FirstAppiumTestNG"/> </classes> </test> <!-- Test --> </suite> <!-- Suite --> Create A New TestNG File Naming The File testng.xml Pasting The XML Script In The New Testng.xml FileTo properly run our TestNG XML file, we need to configure the pom.xml file accordingly. Start by opening your pom.xml file and locating the Maven Surefire Plugin section. Within this section, you’ll need to add the TestNG configuration. Specifically, scroll down to where you see the <version> tag within the Maven Surefire Plugin and insert the following configuration just below it:TestNG Suite Setup (pom.xml)<configuration> <suiteXmlFiles> <suiteXmlFile>testng.xml</suiteXmlFile> </suiteXmlFiles> <testFailureIgnore>false</testFailureIgnore> </configuration> Pasting TestNG XML ConfigurationThis snippet tells Maven to use the testng.xml file to determine which tests to run. The <testFailureIgnore> tag is set to false, ensuring that the build will fail if any test fails, which is often the desired behavior in a continuous integration environment.Once you’ve added this configuration, make sure to save your pom.xml file. With these changes in place, your project is now ready to run with the specified TestNG configuration. Let's open the Terminal in Eclipse so we can execute the Maven command. Type or copy the command mvn test -DsuiteXmlFile=testng.xml into the Terminal. Press Enter to execute. The script should begin running the three scenarios we created earlier. As the tests execute, you should see passing logs appear in the console, indicating successful execution. Pasting Maven Command To Run TestNG Successful Test Results After Running CommandRunning Test: TestNG PluginAlternatively, if you have the TestNG plugin installed on your IDE, you can simply right-click on the test file and choose Run As TestNG. This method provides a quick and easy way to execute your tests without the need to manually configure the XML file. class. Running Test File Using 'Run As TestNG'Running FirstAppiumTestNG ScriptAlright, let’s sit back and enjoy watching the results. In the video below, you’ll see the script in action as it runs via the mvn command. The test executes all three scenarios and they pass successfully! It’s always a great feeling when everything works perfectly, isn’t it? Yay! GIF: Script Is Running TestNG Results Pane TestNG HTML Web ResultsConclusionOrganizing multiple test scenarios in Appium using TestNG is a critical step in building a robust test automation strategy. With TestNG, we can group our test cases logically, execute them in a specific order, and generate detailed reports. This structured approach not only saves time but also minimizes errors, making our testing process more reliable and efficient. Stay tuned for our next topic, where we will delve into Understanding Appium UI Locators.Tagged:Appium Appium - Previous Writing Your First Test Case with Appium Next - Appium Understanding Appium UI Locator Strategies