Appium

Organizing Multiple Test Scenarios in Appium Using TestNG

Estimated reading: 18 minutes 195 views
appium-featured-image

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 Project

Let’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.

add-testng-dependency-to-pom-file
Adding TestNG Dependency To pom.xml
TestNG 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.
appium-copying-class
Copying FirstAppiumTest Class
appium-pasting-firstappiumtest-class
Pasting FirstAppiumTest Class
rename-copied-file-to-firstappiumtestng
Rename Copied File to FirstAppiumTestNG

Importing TestNG Annotations

In the newly created FirstAppiumTestNG class, begin by importing the necessary TestNG annotations. These will include @BeforeClass, @AfterClass, and @Test.

FirstAppiumTestNG.class
import 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 TestNG

So 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

BeforeClass

In 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-method
Moving Desired Capabilities To BeforeClass Method

Test Method

In 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.

appium-testng-test-class
Moving Scenario To Test Method

AfterClass Method

Finally, 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-method
Moving The Closing of the Driver in AfterClass Method
FirstAppiumTestNG.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 & Assertions

Why 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() Test

Next, 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() Test

Finally, 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 Implementation

Here’s the full implementation of the FirstAppiumTestNG file.

FirstAppiumTestNG.class
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.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 Setup

Now 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 -->
appium-testng-create-new-file
Create A New TestNG File
appium-testng-file-name
Naming The File testng.xml
pasting-xml-script-testng
Pasting The XML Script In The New Testng.xml File

To 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>
appium-update-testng-xml-file
Pasting TestNG XML Configuration

This 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.

  1. Let's open the Terminal in Eclipse so we can execute the Maven command.
  2. Type or copy the command mvn test -DsuiteXmlFile=testng.xml into the Terminal.
  3. Press Enter to execute.
  4. The script should begin running the three scenarios we created earlier.
  5. As the tests execute, you should see passing logs appear in the console, indicating successful execution.
appium-mvn-command
Pasting Maven Command To Run TestNG
appium-console-results
Successful Test Results After Running Command

Running Test: TestNG Plugin

Alternatively, 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.

appium-testng-run-via-plugin
Running Test File Using 'Run As TestNG'

Running FirstAppiumTestNG Script

Alright, 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!

appium-running-tesng-test
GIF: Script Is Running
appium-testnt-results-pane
TestNG Results Pane
appium-tesng-html-results
TestNG HTML Web Results

Conclusion

Organizing 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.

Leave a Comment

Share this Doc

Organizing Multiple Test Scenarios in Appium Using TestNG

Or copy link

CONTENTS
Review Your Cart
0
Add Coupon Code
Subtotal
Total Installment Payments
Bundle Discount