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:
[code lang=java]
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();
}
}
}
[/code]
Note here, I’ve created a strong>@Factory constructor with the data provider called parallelDp. Refer here for more about strong>@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:
[code language="xml"]
<!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>
[/code]
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.
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.
Sree, I would like to know more about your issue. Possible to share something which I can re-create.
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.
I got it. Most probably this is due to jvm itself. Refer this article https://rationaleemotions.wordpress.com/2013/01/28/building-a-self-maintaining-grid-environment/ which talks about this and how you can build the self healing mechanism for your grid.
Thanks a lot Vimal
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.
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
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
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?
Got that to work but it executes the test in sequence. How to doi it parallel?
Refer the testng xml in the post that I have mentioned which will clear your question.
Yes, i followed it to a T. Below is the XML and it only executes in sequence:
@Jorge Can you try set the following
@DataProvider(name = “parallelDp”,parallel=true)
This worked for me.
It worked for me, thanks alot
Glad it worked for you
please,give me details step of appium devices configurationgrid with selenium
In what step you are stuck. Kindly call out the steps you tried. It would be helpful for me to help you.
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
I think above error is related to https://github.com/appium/java-client/issues/655, please clarify which version of selenium server and appium java client does this code works for you ?
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 ?
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)