Blog
>
Technology

Appium with Parallel Execution: PART — 2

Shreyas Jain
I
February 17, 2022

Photo by Headway on Unsplash

Setting Up the Plot:

We tried to utilize the devices with fewer changes to the automation code and we started using the devices right away.

The following approaches are my experiences when it comes to moving towards parallel execution. To demonstrate with an example:

  • Source code used :

https://github.com/shreyas18jan/AppiumExample

  • 2 Devices: one Emulator and one real device. (can be scaled for more devices also).

Approach 3: Use Maven SureFire Plugin and Selenium Grid

java -jar selenium-server-standalone-3.9.1.jar -role hub

  • Now you should be able to access this link

http://<YOUR_IP_ADDRESS>:4444/grid/console

  • Update the URL that we used for AndroidDriver object creation to this

http://<YOUR_IP_ADDRESS>:4444/wd/hub

  • Create device-specific JSON files as shown below, Please change the UDID, appPackage, appActivity, and Ports to your need.

{
“capabilities”: [{
“deviceName”: “emulator-5556”,
“udid”: “emulator-5556”,
“systemPort”: 8226,
“automationName”: “uiautomator2”,
“platformName”: “Android”,
“appPackage”: “com.example.androidappexample”,
“appActivity”: “com.example.androidappexample.MainActivity”,
“uiautomator2ServerLaunchTimeout”: 40000,
“maxInstances”: 1
}],
“configuration”: {
“cleanUpCycle”: 2000,
“timeout”: 30000,
“proxy”: “org.openqa.grid.selenium.proxy.DefaultRemoteProxy”,
“maxSession”: 1,
“register”: true,
“registerCycle”: 5000,
“hubPort”: 4444,
“hubHost”: “127.0.0.1”,
“hubProtocol”: “http”
}
}

  • Make use of Appium from the terminal instead of Appium-Desktop. Please export JAVA_HOME and ANDROID_HOME

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_281.jdk/Contents/Home

export ANDROID_HOME=/Users/<USER_HOME>/Library/Android/sdk
appium -p 4723 — nodeconfig ./Device1.json

  • Once you execute this command you can see that Selenium Grid shows a logline “Registered a node http://0.0.0.0:4723". Just like this create another device JSON file with proper details and register it against the Selenium grid.
  • Since I’m using JUnit, Parallel execution will happen at the feature file level, not at the Scenario level. With the help of the SureFire plugin, we can achieve parallel execution. Create separate JUnit Runner and separate Feature files equivalent to the number of devices you have.
    Example: If I have 2 devices, separate the single feature file into 2 feature files and create 2 Runner, where Runner1 refers to the tag in Feature file1 and Runner2 refers to the tag in Feature file2. Add the Runner Details in the SureFire plugin.
  • Add the Surefire Maven dependency in the POM file. Make sure that ThreadCount is equal to the number of devices you have.

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<testSourceDirectory>${project.basedir}/src/main/java</testSourceDirectory>
<includes>
<include>**/AppiumDemoRunnerTestFM10.java</include>
<include>**/AppiumDemoRunnerTestFM3.java</include>
</includes>
<parallel>classes</parallel>
<threadCount>2</threadCount>
<perCoreThreadCount>false</perCoreThreadCount>
</configuration>
</plugin>
</plugins>
</build>

  • Now we need to make sure that these parallel files should not use the same Device and Appium Port. So come up with a logic to pass the correct Port and Device details during execution. One way is to add the details in the Feature file.
    Example: Add device name in the Given Step. i.e,
    Given open the App in emulator-5556
    or
    Given open the App in DEVICE-1.
    Based on the info reaching StepDefinition, StepDefinition takes the decision to pass the required Port and Device details to AndroidDriver Object.
  • After doing all these changes, we just need one maven command to run.

mvn clean test -Dappium.address=http://<SELENIUM_GRID_IP_ADDRESS>:4444/wd/hub

Pros: (Better than Approach 2)

  • Execution time is reduced.
  • Feature file Level parallel execution is present.

Cons:

  • One-time setup is needed to set Selenium Hub and Appium Node Configurations.
  • Separate Runners need to be created to achieve Feature file Level parallel execution.
  • Scenario Level parallel execution is not present.

Note:

Code can be checked here

GitHub - shreyas18jan/AppiumExample at JUNIT_VARIATION_APPROACH3

You can't perform that action at this time. You signed in with another tab or window. You signed out in another tab or…

github.com

Approach 4: Use Maven failsafe Plugin, Cucumber JVM Parallel plugin, and Selenium Grid

java -jar selenium-server-standalone-3.9.1.jar -role hub

  • Now you should be able to access this link

http://<YOUR_IP_ADDRESS>:4444/grid/console

  • Update the URL that we used for AndroidDriver object creation to this

http://<YOUR_IP_ADDRESS>:4444/wd/hub

  • Create device-specific JSON files as shown below, Please change the UDID, appPackage, appActivity, and Ports to your need.

{
“capabilities”: [{
“deviceName”: “emulator-5556”,
“udid”: “emulator-5556”,
“systemPort”: 8226,
“automationName”: “uiautomator2”,
“platformName”: “Android”,
“appPackage”: “com.example.androidappexample”,
“appActivity”: “com.example.androidappexample.MainActivity”,
“uiautomator2ServerLaunchTimeout”: 40000,
“maxInstances”: 1
}],
“configuration”: {
“cleanUpCycle”: 2000,
“timeout”: 30000,
“proxy”: “org.openqa.grid.selenium.proxy.DefaultRemoteProxy”,
“maxSession”: 1,
“register”: true,
“registerCycle”: 5000,
“hubPort”: 4444,
“hubHost”: “127.0.0.1”,
“hubProtocol”: “http”
}
}

  • Make use of Appium from the terminal instead of Appium-Desktop. Please export JAVA_HOME and ANDROID_HOME

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_281.jdk/Contents/Home

export ANDROID_HOME=/Users/<USER_HOME>/Library/Android/sdk
appium -p 4723 — nodeconfig ./Device1.json

  • Once you execute this command you can see that Selenium Grid shows a logline “Registered a node http://0.0.0.0:4723". Just like this create another device JSON file with proper details and register it against the Selenium grid.
  • Create separate Feature files equivalent to the number of devices you have. No need to create multiple Runners.
    Example: If I have 2 devices, separate the single feature file into 2 feature files.
  • Add the following dependency in the POM file. Make sure that ThreadCount is equal to the number of devices you have.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<testSourceDirectory>${project.basedir}/src/main/java</testSourceDirectory>
<includes>
<include>**/AppiumDemoRunner.java</include>
</includes>
<parallel>methods</parallel>
<threadCount>2</threadCount>
<perCoreThreadCount>false</perCoreThreadCount>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.temyers</groupId>
<artifactId>cucumber-jvm-parallel-plugin</artifactId>
<version>5.0.0</version>
<executions>
<execution>
<id>generateRunners</id>
<phase>generate-test-sources</phase>
<goals>
<goal>generateRunners</goal>
</goals>
<configuration>
<glue>
<package>com.example.appium</package>
</glue>
<parallelScheme>FEATURE</parallelScheme>
<featuresDirectory>src/test/java/com/example/appium/features</featuresDirectory>
<customVmTemplate>src/test/resources/cucumber-runner.vm</customVmTemplate>
</configuration>
</execution>
</executions>
</plugin>

  • Now we need to make sure that these parallel files should not use the same Device and Appium Port. So come up with a logic to pass the correct Port and Device details during execution. One way is to add the details in the Feature file.
    Example: Add device name in the Given Step. i.e,
    Given open the App in emulator-5556
    or
    Given open the App in DEVICE-1.
    Based on the info reaching StepDefinition, StepDefinition takes the decision to pass the required Port and Device details to AndroidDriver Object.
  • After doing all these changes, we just need one maven command to run.

mvn clean verify -Dappium.address=http://<SELENIUM_GRID_IP_ADDRESS>:4444/wd/hub

Pros: (Better than Approach 3)

  • Execution time is reduced.
  • Feature file Level parallel execution is present.
  • No Need to create Separate Runner files.

Cons:

  • One-time setup is needed to set Selenium Hub and Appium Node Configurations.
  • Scenario Level parallel execution is not present.

Note:

Code can be checked here

GitHub - shreyas18jan/AppiumExample at JUNIT_VARIATION_APPROACH4

You can't perform that action at this time. You signed in with another tab or window. You signed out in another tab or…

github.com

Approach 5: Use Maven failsafe Plugin, Cucumber JVM Parallel plugin with AppiumDriverLocalService

  • Create separate Feature files equivalent to the number of devices you have. No need to create multiple Runners.
    Example: If I have 2 devices, separate the single feature file into 2 feature files.
  • Add the following dependency in the POM file. Make sure that ThreadCount is equal to the number of devices you have.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<testSourceDirectory>${project.basedir}/src/main/java</testSourceDirectory>
<includes>
<include>**/AppiumDemoRunner.java</include>
</includes>
<parallel>methods</parallel>
<threadCount>2</threadCount>
<perCoreThreadCount>false</perCoreThreadCount>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.temyers</groupId>
<artifactId>cucumber-jvm-parallel-plugin</artifactId>
<version>5.0.0</version>
<executions>
<execution>
<id>generateRunners</id>
<phase>generate-test-sources</phase>
<goals>
<goal>generateRunners</goal>
</goals>
<configuration>
<glue>
<package>com.example.appium</package>
</glue>
<parallelScheme>FEATURE</parallelScheme>
<featuresDirectory>src/test/java/com/example/appium/features</featuresDirectory>
<customVmTemplate>src/test/resources/cucumber-runner.vm</customVmTemplate>
</configuration>
</execution>
</executions>
</plugin>
</executions>
</plugin>

  • Now we need to make sure that these parallel files should not use the same Device and Appium Port. So come up with a logic to pass the correct Port and Device details during execution. One way is to add the details in the Feature file.
    Example: Add device name in the Given Step. i.e,
    Given open the App in emulator-5556
    or
    Given open the App in DEVICE-1.
    Based on the info reaching StepDefinition, StepDefinition takes the decision to pass the required Server Port, System Port, and Device details to AndroidDriver Object.
  • Make sure that you use ThreadLocal for AppiumDriver.

public ThreadLocal<AppiumDriver<MobileElement>> driver = new ThreadLocal<>();

  • To start Appium programmatically, we need to know the following things: Android Home Path, Java Home Path, Appium Command Path, and Node Command Path

Code Snippet to Start the Server:

void startAppiumServer(int serverPort) throws IOException {

InputStream inputStream = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream(“capabilities.properties”);
Properties desiredCapabilitiesProp=new Properties();
desiredCapabilitiesProp.load(inputStream);

HashMap<String, String> environment = new HashMap<>();
environment.put(“ANDROID_HOME”, desiredCapabilitiesProp.getProperty(“appium.android.home”));
environment.put(“JAVA_HOME”, desiredCapabilitiesProp.getProperty(“appium.java.home”));

AppiumServiceBuilder builder = new AppiumServiceBuilder();
builder.withAppiumJS(new File(desiredCapabilitiesProp.getProperty(“appium.command.path”)))
.usingDriverExecutable(new File(desiredCapabilitiesProp.getProperty(“node.command.path”)))
.withIPAddress(“127.0.0.1”)
.usingPort(serverPort)
.withEnvironment(environment);

service = AppiumDriverLocalService.buildService(builder);

// Starting the Service
service.start();
System.out.println(“Appium Service Started !”);
}

Contents of capabilities.properties file:

appium.android.home=<PATH TO ANDROID HOME>
appium.java.home=<PATH TO JAVA HOME>
appium.command.path=<PATH TO APPIUM COMMAND>
node.command.path=<PATH TO NODE COMMAND>

  • After doing all these changes, we just need one maven command to run.

mvn clean verify

Pros: (Better than Approach 3)

  • Execution time is reduced.
  • Feature file Level parallel execution is present.
  • No Need to create Separate Runner files.
  • Only Selenium Hub needs to be set up, code will take care of starting and stopping appium/s.

Cons:

  • Scenario Level parallel execution is not present.

Note:

Code can be checked here

GitHub - shreyas18jan/AppiumExample at JUNIT_VARIATION_APPROACH5

You can't perform that action at this time. You signed in with another tab or window. You signed out in another tab or…

github.com

Conclusion:

The main point when it comes to Mobile Native App/ Hybrid App is that we cannot open more than one instance of the App on the same device.
Appium makes One-to-One Mapping to the Device with AdminPort+SystemPort.

If the execution time needs to be reduced, then we need to have more devices in hand.
A combination of Emulators and Real Devices will definitely help the Automation process.

If you are using TestNG instead of JUnit like the above scenario, We can directly jump to Approach 5 with Parallel Execution. In TestNG making changes to run the cases in Parallel is very easy.

The above approaches are the different ways to Deal with Parallel Execution in Mobile Automation with Appium.

QA
Automation Testing

About Quinbay

Quinbay is a dynamic one stop technology company driven by the passion to disrupt technology today and define the future.
We private label and create digital future tech platforms for you.

Digitized . Automated . Intelligent