How to Setup Your Own Mobile Device Lab

Hi all, In this article, I am going to explain how to create a basic mobile device lab (a.k.a device farm) for your mobile automation projects.

First of all, you need 2 tools and mobile devices:

Grid allows you to scale by distributing tests on several machines (parallel execution). You will also run one Appium node for each mobile device that you will connect to your mobile device lab. At the end, you will have an infrastructure as below.

device farm

Steps to Create a Mobile Device Lab are as follows:

1- Setting up a full running Selenium Grid Infrastructure

2- Creating JSON file for Appium to manage our mobile devices

3- Running Appium Server for each device

4- Changing project structure

Setting up a Fully Running Selenium Grid Infrastructure

Selenium Grid (SG) comes in a *.jar file and it runs on the console. There are some parameters that you need to configure while running the Selenium Grid. The most basic ones explained in the example. By changing the “Port” parameter, you modify the default port of SG. Role parameter is set as “hub” parameter, and it defines that SG behaves as a central request collection point and it receives all the test requests and distributes them the right nodes.

java -jar selenium-server-standalone-2.53.0.jar -port 4444 -role hub

After initialization of above command, point your browser to http://localhost:4444/grid/console URL and see that Selenium Grid is fully functional.

Creating JSON File for Appium to Manage our Mobile Devices

In this step, we need to create *.json files for each mobile devices. Those files have two parts. The first part is “Capabilities” and it keeps specific information about mobile devices like their device ids, browsers, OS names and OS versions. The second part is “Configuration,” and it comprises of information about the Selenium Hub.

Selenium Grid matches test requests with the devices by using definitions in capabilities part. In below at JSON file’s capabilities part, three parameters hold crucial information of the device.

The other parameters are host, port, URL, hubPort, hubHost and you can also change them at Configuration part. You need to modify them according to your infrastructure. Host and port are host IP and port of your Appium server.

After creating this file, save it as “node-devicename.json”. For each mobile device, you need to create a specific file by changing the parameters that I explained above.

{
	"capabilities": [
    	{
			"deviceName": "021YHB2133086676",
			"platformName": "Android",
			"version": "5.1",
			"browserName":"Chrome",
			"maxInstances": 1
    	}
	],
	"configuration": {
			"cleanUpCycle": 2000,
			"timeout": 30000,
			"proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
			"host": "192.168.101.2",
			"port": 4726,
			"maxSession": 1,
			"register": true,
			"url": "http://192.168.101.2:4726/wd/hub",
			"registerCycle": 5000,
			"hubPort": 4444,
			"hubHost": "127.0.0.1"
	}
}

To get your device’s UDID, you need to turn on “Developer Settings” on your mobile device and runadb devices” command on the console. Turning on the “Developer Settings” of a mobile device is varying. Thus, you need to find how to do this for your devices in Google ;)

Update:

If you are going to add an iOS device, you can create another json file with below configs. AutomationName is crucial for iOS automation. The other configuration may depend on the device you use.

{
 "capabilities": [
    	{
 "deviceName": "iphone",
 "platformName": "iOS",
 "automationName":"XCUITest",
 "platformVersion": "12.14",
 "udid":"713501aadb03d733a242f7abf97cee5be51417be",
 "browserName":"Safari",
 "maxInstances": 1
    	}
 ],
 "configuration": {
 "cleanUpCycle": 2000,
 "timeout": 30000,
 "proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
 "host": "127.0.0.1",
 "port": 4725,
 "maxSession": 1,
 "register": true,
 "url": "http://127.0.0.1:4725/wd/hub",
 "registerCycle": 5000,
 "hubPort": 4444,
 "hubHost": "127.0.0.1"
 }
}

 

Running Appium Server for Each Mobile Device

In this step, we will configure Appium Nodes. Appium can only handle one mobile device, so we need several Appium servers to interact with all devices as shown in the first picture. Thus, we need to create a small batch file which triggers Appium. This command must be executed in Appium’s folder. That command is shown below:

node.exe node_modules\appium\bin\appium.js 
--session-override 
--nodeconfig c:\selenium-server\node-huaweii.json 
-p 4726 
--bootstrap-port 2252 
--udid 021YHB2133086676

As you can see, there are many parameters that we need to send Appium server. NodeConfig parameter points the path to the JSON file. “P” and “Bootstrap-port” parameters override the default ports that Appium runs. “UDID” is the device id that Appium will interact.

When you run that command, point your browser to Selenium Grid landing page(http://localhost:4444/grid/console). You will see Appium servers are running properly.

device lab

Changing Project Structure for Mobile Device Lab

This part is based on a project that I developed by using Java and TestNG. The below configuration is for that project.

Changing TestNG.xml File

At first, you need to modify your testNG.xml file. You can manage your test suites with this .xml file. For every device you have, you’ll replicate your test tag. In this way, you will pass different parameters to your RemoteWebDriver and run your tests on a specific device.

You need to set “Thread-count” parameter to your total device number in your device lab.

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

<suite name="RunAll Test" parallel="tests" thread-count="4">

    <test name="Test-Nexus">
   	 <parameter name="browserName" value="Chrome" />
   	 <parameter name="platform" value="Android" />
   	 <parameter name="deviceName_" value="ZX1G523QQF" />
   	 <parameter name="version" value="6.0.1" />
   	 <classes>
   		 <class name="com.automation.testapp.tests.TestFactory" />
   	 </classes>
    </test>
    
    <test name="Test-Samsung">
   	 <parameter name="browserName" value="Chrome" />
   	 <parameter name="platform" value="Android" />
   	 <parameter name="deviceName_" value="004f0435" />
   	 <parameter name="version" value="4.4.2" />
   	 <classes>
   		 <class name="com.automation.testapp.tests.TestFactory" />
   	 </classes>
    </test>
    
    <test name="Test-Huaweii">
   	 <parameter name="browserName" value="Chrome" />
   	 <parameter name="platform" value="Android" />
   	 <parameter name="deviceName_" value="021YHB2133086676" />
   	 <parameter name="version" value="5.1" />
   	 <classes>
   		 <class name="com.automation.testapp.tests.TestFactory" />
   	 </classes>
    </test>
    <test name="Test-Genymotion">
   	 <parameter name="browserName" value="Chrome" />
   	 <parameter name="platform" value="Android" />
   	 <parameter name="deviceName_" value="192.168.56.101:5555" />
   	 <parameter name="version" value="5.2" />
   	 <classes>
   		 <class name="com.automation.testapp.tests.TestFactory" />
   	 </classes>
    </test>
</suite>

Changing Java Code

In automation code, we get parameters from our TestNG.xml file and pass them to the Android, iOS, Remote driver. Thus, we need to add “@Parameter” annotation above our test methods, and we can use them in those test methods. In this way, we can use those parameters in DesiredCapabilities Object.

I would suggest you to set autoGrantPermissions and autoAcceptAlerts flags to true so you don’t have to deal with any warning pop-up or alert like “Storage Permission etc”.

@BeforeTest(alwaysRun = true)
 @Parameters({ "deviceName_", "browserName", "platform", "version" })
    public void AndroidDriverSet(String device, String browser,
   		 String platform, String version) {
   	 DesiredCapabilities capabilities = new DesiredCapabilities();
   	 capabilities.setCapability("deviceName", device);
   	 capabilities.setCapability("device", device);
   	 capabilities.setCapability(CapabilityType.VERSION, version);
   	 capabilities.setCapability("platformName", platform);
   	 capabilities.setCapability("appPackage", “app.package.dummyName”);
   	 capabilities.setCapability("appActivity", “app.activity.dummy”);
         capabilities.setCapability("autoAcceptAlerts", true);
         capabilities.setCapability("autoGrantPermissions", true);
   	 try {
   		 driver = new AndroidDriver(new URL(“HUB_URL),
   				 capabilities);
   	 } catch (MalformedURLException e) {
   		 System.out.println("Please check the local Appium URL");
   	 }
    }

To fully automate your process, I suggest you use a Continuous Integration tool to trigger test runs. I used Maven as a build manager.

At last, everything is configured and ready to run, hit “Run” button on Jenkins (CI tool) and see all your devices will run the same test in parallel. Automate this process in parallel makes us a happy tester :)

Note:
If you execute more than one thread for your parallel test runs, please avoid using Singleton Design Pattern in your PageObjects. This implementation causes some weird behavior during test execution. It is better to use ThreadLocal structure so RemoteWebDriver object becomes thread-safe.

You can download my demo project on https://github.com/canb0/MobileDeviceLab

Video Link: https://vimeo.com/183266547

You can check the 2018 Edition of Wireless Mobile Device Farm Article!
http://www.swtestacademy.com/appium-parallel-tests/

Thanks.

12 thoughts on “How to Setup Your Own Mobile Device Lab”

  1. Hello Canberk,

    It was a pretty informative writing, I need to just confirm few things.
    Appium can handle only device interaction, agree, and you have suggested to write a batch script.
    – Cant we run the same appium server by providing different ports for different devices?
    – If several appium are required then can we run all on single machine? if yes then what will be the configurations?
    – If we are providing device capabilities and configurations in device.json files then why we are gain using the port and udid in batch file? How to overcome this
    – To runn all nodes appium configurations in single batch file then how can we configure all?
    – Why we are using bootstrap port in batch file?

    I will be waiting for your comment.

    Thanks
    Rafique

    Reply
    • Hi Muhammad,

      You should many appium server with regards to your device number. One server can only handle one mobile device. You cannot run an appium server with different port.

      In this example i have run all appium servers in one laptop. I suggest you to get Mac’s. One mini mac can handle up to 15-20 machines.

      We cannot run all appium server in one batch. Batch are sequencial applications. It cannot run the second appium server if the first one is not shut down.

      Bootstarp port is for rmi communication. It cant be the same for every appium server. You need to modify it for every appium that you run.

      Hope those answers help you

      Reply
    • Thanks so much for the neat and detailed explaination i really liked it,

      But i have one question do we really need selenium grid for parallel test,

      Why we just dont trigger appium server with different port number and different bootstrap programatically and pass our paremeters from the xml file
      For example pass url=0.0.0.0
      Pass bootstrap = 100
      , 200 …etc for each device

      Reply
  2. Good afternoon

    Canberk Akduygu we have followed your tutoriual step by step, we have implemented the session for two mobiles, but at the moment of launching the script, the request opens in both mobile but at the moment of following the step by step only does it in one, not We know that more to do, you can guide us.

    Thank you so much.

    Reply
        • Thank you so much but I could not understand how it is possible. You need multiple nodes and each node needs specific appium server. If you can do it, please write an article about that and I would like to read it Mark. The article you shared is pretty similar to ours. One selenium grid server, multiple nodes, each node has its own appium server. Each node has a specific node.json config as well. Grid Server (hub) is kind of load balancer and the nodes are connected to hub. In your code, you are sending your requests to the hub and hub distributes them to the nodes based on a networking algorithm which is probably round-robin. Thus, you need multiple nodes which can be either a website or mobile device and each mobile device needs a specific appium server. It is also very clearly showed on the architecture topology pictures in the article.

          Reply
  3. am using selenium grid 3.8.1 , and Appium 1.14.0 ,Java client is 6.1.0, and Selenium 3.13.0 , if I run through grid am getting an “it’s impossible to create a session ” , if i run in directly without using grid, it’s working fine, what could be the problem , it’s a grid issue?

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.