How to Automate Appium Java Tests In Parallel Using TestNG
This article will walk through how to automate Appium tests in parallel against our real devices using TestNG Java sample tests.
Join the DZone community and get the full member experience.
Join For FreeThe beauty of Appium for mobile testing is that its tests can be written in any programming language including Python, Ruby, Java, JavaScript, and C#. While we have covered extensive Appium tutorials, in this article, we'll walk through how to automate Appium tests in parallel against our real devices using TestNG Java sample tests.
You may also like: How to Run a Selenium Test With TestNG
What Is and Why to Use TestNG?
TestNG, where NG denotes Next Generation, is an automated testing framework that is inspired by both JUnit and NUnit.
It is designed to simplify a wide range of testing needs including unit testing, functional testing, and integration testing. It gives mobile developers and testers the ability to write more flexible and powerful tests.
Benefits of Using TestNG
TestNG is similar to JUnit but introduces some new features that make it more powerful and easier to use. Below are some of the benefits Appium Java users can enjoy with TestNG:
- More annotations: TestNG has an extensive choice of annotations. See a full list of annotations available in TestNG.
- Test Grouping: The
groups
attribute with the @Test annotation eases the grouping of test cases. - Test Prioritization: Using the
priority
attribute to set different priorities for each test case. - Parameterized Tests: Using parameterized tests makes it easy to run the same test over and over using different values.
- Parallel Testing: It's possible and easy to parallelize test execution with the
parallel
attribute. We're going to use it in our sample below.
The Basic Setup for Running Appium Tests in Java Using TestNG
First of all, to run tests simultaneously on different devices, you should use ThreadLocal in order to save several drivers at one time.
If you use only one driver instance, the test will be run on the one device only because the diver will use the last created session.
Firstly, you should create the ThreadLocal object:
private static ThreadLocal<RemoteWebDriver> driver = new ThreadLocal<>();
Then, you have to add the driver in ThreadLocal using the driver.set(...)
method:
driver.set(new RemoteWebDriver(new URL("remote_hub_url_here"), capabilities));
Now, if you want to get the driver which is active at the moment, you can use the driver.get()
method:
public static WebDriver getDriver() {
return driver.get();
}
Dealing With Appium Desired Capabilities
In order to run RemoteWebDriver, you should install the needed capabilities. They can vary depending on the device where the test has to be performed. Mostly, specialists use the basic ones, such as deviceName
, platformName
, browserName
, platformVersion
.
Here we have capabilities that are needed to run the tests on Bitbar cloud for Android devices:
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("bitbar_apiKey", <YOUR_BITBAR_API_KEY>);
capabilities.setCapability("bitbar_testrun", "Bitbar test run");
capabilities.setCapability("bitbar_project", "Bitbar test project");
capabilities.setCapability("bitbar_device", bitbarDevice);
capabilities.setCapability("browserName", browserName);
capabilities.setCapability("platformName", platformName);
capabilities.setCapability("deviceName", deviceName);
Properties will be as follows:
bitbar_device = Google Pixel XL
browser_name = chrome
platform_name = Android
device_name = Android Phone
In the case with iOS devices, you have to add one more capability:
capabilities.setCapability("automationName", automationName);
Properties file will be like this:
bitbar_device = iPhone7 11.3.1 (ios02)
browser_name = safari
platform_name = iOS
device_name = iPhone device
automation_name = XCUITest
The final configuration of capabilities will be the following:
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("bitbar_apiKey", <YOUR_BITBAR_API_KEY>);
capabilities.setCapability("bitbar_testrun", this.getClass().getSimpleName());
capabilities.setCapability("bitbar_project", xmlTestName);
capabilities.setCapability("bitbar_device", bitbarDevice);
capabilities.setCapability("browserName", browserName);
capabilities.setCapability("platformName", platformName);
capabilities.setCapability("deviceName", deviceName);
if (automationName != null)
capabilities.setCapability("automationName", automationName);
driver.set(new RemoteWebDriver(new URL("https://appium.bitbar.com/wd/hub/"),
capabilities));
To get more information about needed capabilities for various devices, please visit Bitbar Capabilities Creator.
Get Started With a Simple Appium Test Using Java TestNG
Now let's create a simple Google search test:
import base.BaseTest;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.util.List;
public class SimpleGoogleTest extends BaseTest {
private static final String GOOGLE_SEARCH_URL = "https://www.google.com/";
private static By searchInput = By.cssSelector("[name='q']");
private static By searchButton = By.cssSelector(".Tg7LZd");
private static By searchResultTable = By.id("cnt");
private static By searchResultItemHeader = By.cssSelector("#rso div.zlBHuf");
@Test
public void searchForBitbar() throws InterruptedException {
// Get driver instance
WebDriver driver = BaseTest.getDriver();
// Open main Google Search page
driver.get(GOOGLE_SEARCH_URL);
Assert.assertEquals(driver.getCurrentUrl(), GOOGLE_SEARCH_URL);
// Input "Bitbar" search term, click on search button
//and wait for page to be loaded
driver.findElement(searchInput).sendKeys("Bitbar");
driver.findElement(searchButton).click();
Thread.sleep(2000);
// Check that Search result table present with search results
Assert.assertTrue(driver.findElements(searchResultTable).size() > 0);
// Check that at least one search result item contains word "Bitbar"
List<WebElement> resultItems = driver.findElements(searchResultItemHeader);
boolean isPresent = false;
for (WebElement item : resultItems) {
if (item.getText().contains("Bitbar"))
isPresent = true;
}
Assert.assertTrue(isPresent);
}
}
Also, we will create a test suite to run two tests simultaneously:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Test Suite" thread-count="2" parallel="tests">
<test name="Simple Google Test Google Pixel XL">
<parameter name="Device" value="GooglePixelXL"/>
<classes>
<class name="SimpleGoogleTest"/>
</classes>
</test>
<test name="Simple Google Test iPhone7 11.3.1">
<parameter name="Device" value="iPhone7_11.3.1"/>
<classes>
<class name="SimpleGoogleTest"/>
</classes>
</test>
</suite>
File with driver configurations will be as follows:
package base;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.ITestContext;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Parameters;
import utils.Constants;
import utils.Reporter;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
public class BaseTest {
private static ThreadLocal<RemoteWebDriver> driver = new ThreadLocal<>();
private String deviceName;
private String bitbarDevice;
private String browserName;
private String platformName;
private String automationName;
@BeforeMethod
@Parameters(value = {"Device"})
public void setUp(String device, ITestContext context) throws MalformedURLException {
setupRemoteDriver(device, context.getCurrentXmlTest().getName());
getDriver().manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}
private void setupRemoteDriver(String device, String xmlTestName) throws MalformedURLException {
loadProperties(device);
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("bitbar_apiKey", <YOUR_BITBAR_API_KEY>);
capabilities.setCapability("bitbar_testrun", this.getClass().getSimpleName());
capabilities.setCapability("bitbar_project", xmlTestName);
capabilities.setCapability("bitbar_device", bitbarDevice);
capabilities.setCapability("browserName", browserName);
capabilities.setCapability("platformName", platformName);
capabilities.setCapability("deviceName", deviceName);
if (automationName != null)
capabilities.setCapability("automationName", automationName);
driver.set(new RemoteWebDriver(new URL("https://appium.bitbar.com/wd/hub/"), capabilities));
}
private void loadProperties(String device) {
FileInputStream propertiesFIS;
Properties properties = new Properties();
String propertiesFilePath = String.format("src/test/resources/properties/%s.properties", device);
try {
propertiesFIS = new FileInputStream(propertiesFilePath);
properties.load(propertiesFIS);
bitbarDevice = properties.getProperty("bitbar_device");
browserName = properties.getProperty("browser_name");
platformName = properties.getProperty("platform_name");
deviceName = properties.getProperty("device_name");
if (properties.getProperty("automation_name") != null)
automationName = properties.getProperty("automation_name");
} catch (IOException e) {
Reporter.err("Properties file is missing or invalid! Check path to file: " + propertiesFilePath);
System.exit(0);
}
}
static WebDriver getDriver() {
return driver.get();
}
@AfterMethod
public void tearDown() {
if (getDriver() != null)
getDriver().quit();
}
}
Conclusion
TestNG is a great testing framework of choice for Appium tests written in Java. In case you have implemented your Appium TestNG tests and are looking for a mobile app testing platform for automating it in parallel, try to run your tests on Bitbar Cloud.
Further Reading
Published at DZone with permission of Lingkai Shao. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments