[Android] How to perform parallel testing in Appium using Selenium Grid.

Introduction:

We all known that to perform parallel execution of same script in multiple clients we use Selenium Grid.(There is another way using testNG, which will be added in next blog) This works in form of HUB and node architecture. Will have to host one Selenium standalone server and register multiple nodes. Here we will see execution in two real devices. One will be connected via wi-fi and the other one is via USB cable.

Required Jar and executables:
Appium 1.7.2 (Standalone installation).
selenium-server-standalone-X.X.X.jar (This particular tutorial used 3.7.1 version)
selenium-java-3.9.1
java client 6.0.0-BETA2
TestNG 6.11.

In this tutorial I have used DemoApi app for testing.

Steps:
  1. Your device should have usb debugging enabled and connected to wifi.
  2. Note down the OS version and Android version from each device.
  3. To check IP address from Settings >> Wifi >> Advanced >> IP Address 
  4. To check OS version of devices from Settings >> About phone >> Android version 
  5. Now will have to create Json file for our devices (nodes) with capabilities and configuration.
  6. Example: I have one device which is Nexus 4 with 5.1.1 OS installed.
  7. Now create a new Json file with named Android-LG-Nexus4.json

The file contains are: 
Note: You have change "deviceName": and port accordingly.

{
  "capabilities":
      [
        {
            "deviceName": "192.168.20.32:5656",
            "platformName": "Android",
            "browserName":"Android-LG-Nexus4",
            "platformVersion": "5.1.1",
            "maxInstances": 1
        }
      ],
  "configuration":
  {
    "cleanUpCycle":2000,
    "timeout":30000,
    "proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
    "url":"http://127.0.0.1:5000/wd/hub",
    "host": "127.0.0.1",
    "port": 5000,
    "maxSession": 1,
    "register": true,
    "registerCycle": 5000,
    "hubPort": "4444",
    "hubHost": "127.0.0.1"
  }
}

Similarly do it for other device.
Its recommended that you keep json files, selenium standalone jar into a single folder.
Now create a bat file to trigger selenium Grid server with below command.
 java -jar selenium-server-standalone-3.7.1.jar -role hub

Connect your devices to Wifi and system.
  1. Connect your first device using USB.
  2. Open command prompt and check if devices is connected using below command.
  3. adb devices
  4. Type adb tcpip 5656 --> This will assign port number to your device.
  5. Type adb connect 192.168.20.32:5656  --> This command has ip your device and assigned port number.
  6. Now disconnect your from USB and type adb devices to check if device is detected by adb.

Refer below screenshot.


Note: No need to do it for second device because we will execute over USB.

Class Creation.

Create a BaseTest class which has all desired capabilities. 

package AppiumGrid;

import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.remote.MobileCapabilityType;

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

import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Parameters;

public class BaseTest {

    public AndroidDriver<MobileElement> driver;
    public WebDriverWait wait;
    private ThreadLocalDriver threadLocalDriver = new ThreadLocalDriver();
   

    @BeforeMethod
    @Parameters({"deviceName", "platformVersion"})
    public void setup (String deviceName, String platformVersion) throws MalformedURLException
 {
        DesiredCapabilities caps = new DesiredCapabilities();
        caps.setCapability("deviceName", deviceName);
        caps.setCapability("platformVersion", platformVersion);
        caps.setCapability("platformName", "Android");
        caps.setCapability("appPackage", "io.appium.android.apis");
        caps.setCapability("appActivity",".ApiDemos");
        caps.setCapability("skipUnlock","true");
        caps.setCapability("noReset","false");
        threadLocalDriver.setTLDriver(new AndroidDriver<MobileElement>(new URL("http://127.0.0.1:4444/wd/hub"),caps));
        driver = threadLocalDriver.getTLDriver();
        wait = new WebDriverWait(driver, 10);
   }

    @AfterMethod
    public synchronized void teardown(){
        driver.quit();
    }
}

Create a ThreadLocalDriver class for thread safety.

package AppiumGrid;

import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;

public class ThreadLocalDriver {

private static ThreadLocal<AndroidDriver<MobileElement>> tlDriver = new ThreadLocal<>();
 
    //OB: Setting AndroidDriver to ThreadLocal driver 
    public synchronized void setTLDriver(AndroidDriver driver) {
        tlDriver.set(driver);
    }

    public synchronized AndroidDriver getTLDriver() {
        return tlDriver.get();
    }
}

Create Test case class.
package AppiumGrid;

import io.appium.java_client.android.AndroidTouchAction;
import io.appium.java_client.touch.offset.ElementOption;
import io.appium.java_client.touch.offset.PointOption;

import org.openqa.selenium.By;
import org.testng.annotations.Test;

public class TestGrid extends BaseTest{
@Test
public void preference()
{
driver.findElementByAndroidUIAutomator("new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().textContains(\"Views\").instance(0))");
PointOption<ElementOption> point = ElementOption.element(driver.findElement(By.xpath("//android.widget.TextView[@text='Views']")));
new AndroidTouchAction(driver).tap(point).perform();
driver.findElementByAndroidUIAutomator("new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().textContains(\"WebView\").instance(0))");
driver.findElement(By.xpath("//android.widget.TextView[@text='WebView']")).click();
}


}

Create a TextNG file.
Note: You have mention correct ip address, port number and platformVersion as per your device. Any wrong value will lead to test failure.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">

<suite name="IsinOlsun-Android-Test-Suite" parallel="tests"
thread-count="5">

<!--Nexus4_Settings -->
<test name="Test-LG-Nexus4" parallel="classes" thread-count="5">
<parameter name="deviceName" value="192.168.20.32:5656" />
<parameter name="platformVersion" value="5.1.1" />
<classes>
<class name="AppiumGrid.TestGrid" />
</classes>
</test>

<!--Xiaomi_Note3_Settings -->
<test name="Test-Xiomi-Note3" parallel="classes" thread-count="5">
<parameter name="deviceName" value="192.168.20.46:5657" />
<parameter name="platformVersion" value="6.0.1" />
<classes>
<class name="AppiumGrid.TestGrid" />
</classes>
</test>

</suite>

Now run the starthub.bat file to lunch selenium grid server.

  • If you are running on two devices will have to configure in two appium server instance.
  • Launch appium server and navigate to advance tab.
  • Enter Server port as mentioned json file (Ex: 5000)
  • Mention node config file path, this should be the full path json file. (Ex: F:\Packages\AppiumGrid\Android-LG-Nexus4.json)
  • Check the check box  Allow Session Override.
  • Start the appium server, it will start the appium server.

Follow the same steps for other device as well. Check the below screenshot.


Check the below screenshot (Grid console) to confirm whether both nodes are registered successfully.


Open your browser and type URL as http://localhost:4444/grid/console
It will show configured nodes and shown in screenshot.


Now Go back to your project run the testNg file. It will start triggering parallel execution.

If any difficulties please do let me know in comments.

Thank You!


Comments

  1. Extremely helpful. Thanks for sharing!

    ReplyDelete
  2. code runs only in emulator and doesnt run in device connected through USB.

    ReplyDelete
    Replies
    1. Please make sure your device pointed to correct configuration file.

      Delete
  3. can we use
    java client 4.1.2
    appium server 1.7.1 and can we use any selenium-server-standalone and selenium-java for parallel execution ?

    ReplyDelete
    Replies
    1. Its recommended that to use last stable version of java client. 5.0.4

      Delete
  4. Thanks Siddharth for the explanation.
    I have query as practice I am running on single device...and through code I am launching the sever,
    In above you have mentioned that two appium server instance need to be initated.
    Is that possible without manual launch?

    ReplyDelete
  5. good job really useful i tried to do same but im encountering some issue it shows me this error

    ... TestNG 6.14.3 by Cédric Beust (cedric@beust.com)
    ...

    org.openqa.selenium.SessionNotCreatedException: Unable to create a new remote session. Please check the server log for more details. Original error: Unable to parse remote response

    im using testng version 6.14.3
    java client 7.0.0
    selenium stand alone 3.11.0 and also tried selenium-server-standalone-3.141.59 i got same result

    also want to know incase if multiple tests how u can prevent driver from tearing down until other device finish test cuz after one of the device finishing the test it teardown so it make other device fail in the test

    ReplyDelete
  6. How to impement above using pagefactory pom

    ReplyDelete

Post a Comment

Popular posts from this blog

Install and Invoke App.

How to execute appium scripts in could (Saucelabs)