Appium Parallel Execution using TestNG

This is the follow-up post on the Selenium Grid for Appium mobile automation.

Continuing from the example, I hope you have grid hub running with two various appium nodes which has unique applicationName.

This post will focus on showing you on how we execute same tests across multiple devices in parallel. Because, often as test engineers, we have to sign-off our tests in various mobile platforms and devices. Let’s get into action.

Create a TestNG class as follows:

package com.vimalselvam.appium;

import io.appium.java_client.MobileBy;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.remote.MobileCapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.*;

import java.net.MalformedURLException;
import java.net.URL;

public class AppiumTest {

 private AndroidDriver driver;
 private String applicationName;

 @Factory(dataProvider = "parallelDp")
 public AppiumTest(String applicationName) {
   this.applicationName = applicationName;
 }

 @DataProvider(name = "parallelDp")
 public static Object[][] parallelDp() {
   return new Object[][] {
     {"Samsung S4"},
     {"Samsung S5"}
   };
 }

 @BeforeClass
 public void setup() throws MalformedURLException {
   DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
   desiredCapabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "ANDROID");
   desiredCapabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "ANDROID");
   desiredCapabilities.setCapability("applicationName", this.applicationName);
   desiredCapabilities.setCapability(MobileCapabilityType.APP, "https://github.com/appium/java-client/raw/master/src/test/java/io/appium/java_client/ApiDemos-debug.apk");
   driver = new AndroidDriver(new URL("http://127.0.0.1:4444/wd/hub"), desiredCapabilities);
 }

 @Test
 public void launchTest() throws InterruptedException {
   System.err.println("Thread id: " + Thread.currentThread().getId());
   Thread.sleep(10000);
 }

 @Test(dependsOnMethods = {"launchTest"})
 public void clickTest() {
   driver.findElementById("android:id/content")
   .findElement(MobileBy.AccessibilityId("Graphics")).click();
 }

 @AfterClass
 public void teardown() {
   if (driver != null) {
     driver.quit();
   }
 }
}

Note here, I’ve created a @Factory constructor with the data provider called parallelDp. Refer here for more about @Factory. The data provider method produces two String objects of the applicationName which are the same as that I had created during my appium node configuration. Make sure the applicationName here are matches with your node configurations.

I am sure you don’t want me to explain the rest of the test code which simply explains by itself. Let’s move on.

Now create your TestNG Suite xml file as follows:

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Test" verbose="1" data-provider-thread-count="2" thread-count="2" parallel="classes">
    <test name="TestClass" thread-count="2" parallel="instances">
        <classes>
            <class name="com.vimalselvam.appium.AppiumTest" />
        </classes>
    </test>
</suite>

I’ve set the suite parallel attribute as classes, so that it will create two instances of my test class in parallel as specified in my thread-count. That’s it, execute and see the magic in the below video.

21 Replies to “Appium Parallel Execution using TestNG”

  1. HI Vimal , Thanks for the article. How to handle threadsafety issues with appium grid. ex: we use static methods due to this grid execution is not stable. Please provide your comments.

      1. issue: script execution s not stable if we ran huge regression test using appium grid . some times it is executing fine and some time execution failed . i found this is due to thread safety and i used static methods.

  2. Hi Vimal,

    Great article …We are working with perfecto as of now and now switching on appium..Is dere any wayout to connect to adb devices over wifi rather than through usb….We have Client restrcition to plugin the device.We have devices available with us and wifi.

  3. Great Article Vimal, but with your code i get the following error in Eclipse.
    Can’t invoke public java.lang.Object[][] AndroidParallel.TwoAtOnce.parallelDp(): either make it static or add a no-args constructor to your class. This is my code:

    public class TwoAtOnce {

    private AndroidDriver driver;
    private String applicationName;
    
    @Factory(dataProvider = "parallelDp")
    public TwoAtOnce(String applicationName) {
    this.applicationName = applicationName;
     }
    
    @DataProvider(name = "parallelDp")
    public Object[][] parallelDp() {
    return new Object[][] {
    {"Samsung S5"},
    {"Samsung S5 Mini"}
    };
     }
    

    @BeforeClass
    public void Setup() throws MalformedURLException {
    DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
    desiredCapabilities.setCapability(MobileCapabilityType.DEVICE_NAME, “ANDROID”);
    desiredCapabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, “ANDROID”);
    desiredCapabilities.setCapability(“applicationName”, this.applicationName);
    desiredCapabilities.setCapability(MobileCapabilityType.APP, “C:/Users/qtb8926/Desktop/one_one_app-north_america-1162.31e195c-downstream_with_certs.apk”);
    driver = new AndroidDriver(new URL(“http://127.0.0.1:4444/wd/hub”), desiredCapabilities);
    }

    How do i resolve this error so ic an run parallel executions? Thanks in advance

    1. I got it to work, as i what i needed to do was input public “static” Object[][] parallelDp() {
      But now i get the error that SessionNotCreatedException

      1. Glad you solved the data provider issue. The session not created might be due to several reasons. What happens when you run parallel without grid?

          1. @Jorge Can you try set the following
            @DataProvider(name = “parallelDp”,parallel=true)
            This worked for me.

  4. Hi Vimal,

    Do you have working project in github, I’m trying to follow same steps but getting below errors

    2017-07-25 14:04:04.307:WARN:osjs.HttpChannel:qtp1989184704-26: /wd/hub/session
    java.io.IOException: org.openqa.grid.common.exception.GridException: Cannot extract a capabilities from the request: {“capabilities”:[{“desiredCapabilities”:{“app”:”/Users/vikram-anna/Documents/ApiDemos-debug.apk”,”platformName”:”Android”,”deviceName”:”ANDROID”,”applicationName”:”dummy_Android_1″}},{“requiredCapabilities”:{}}],”desiredCapabilities”:{“app”:”/Users/vikram-anna/Documents/ApiDemos-debug.apk”,”platformName”:”Android”,”deviceName”:”ANDROID”,”applicationName”:”dummy_Android_1″},”requiredCapabilities”:{}}

    Caused by:
    java.lang.ClassCastException: com.google.gson.JsonArray cannot be cast to com.google.gson.JsonObject
    at com.google.gson.JsonObject.getAsJsonObject(JsonObject.java:191)
    at org.openqa.grid.web.servlet.handler.WebDriverRequest.extractDesiredCapability(WebDriverRequest.java:69)

    Any thoughts what may be going wrong with my setup ?
    I’ve below in my pom.xml

    com.googlecode.json-simple
    json-simple
    1.1

  5. I could work around above errors with Selenium Server 2.53.1 & latest versions of appium server and java client.

    But the test is only running on single simulator, I have double checked that setup is correct.

    can you please upload sample working whole project in github to try out ?

  6. driver = new AndroidDriver(new URL(“http://127.0.0.1:4444/wd/hub”), desiredCapabilities);

    throwing below error

    java.lang.NoSuchMethodError: com.google.common.base.Throwables.throwIfUnchecked(Ljava/lang/Throwable;)V
    at io.appium.java_client.remote.AppiumCommandExecutor.execute(AppiumCommandExecutor.java:176)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:644)
    at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:42)
    at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1)
    at io.appium.java_client.android.AndroidDriver.execute(AndroidDriver.java:1)
    at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:249)
    at org.openqa.selenium.remote.RemoteWebDriver.(RemoteWebDriver.java:131)
    at org.openqa.selenium.remote.RemoteWebDriver.(RemoteWebDriver.java:144)
    at io.appium.java_client.DefaultGenericMobileDriver.(DefaultGenericMobileDriver.java:38)
    at io.appium.java_client.AppiumDriver.(AppiumDriver.java:88)
    at io.appium.java_client.AppiumDriver.(AppiumDriver.java:112)
    at io.appium.java_client.android.AndroidDriver.(AndroidDriver.java:73)
    at com.serenity.appium.poc.test_classes.AppiumParallelTest.setup(AppiumParallelTest.java:53)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85)
    at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:510)
    at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:211)
    at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:138)
    at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:170)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:104)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

Leave a Reply