How to Set Up Appium Desired Capabilities From a JSON File

Rommel Malqued
Geek Culture
Published in
6 min readApr 8, 2021

There are many ways of doing things. The same goes with how we set up our desired capabilities for our appium driver. The simplest way is like the image above. We create a DesiredCapabilities object and set the capabilities we want for our appium driver using the setCapability() method. Or if you have multiple sets of desired capabilities you can place them in a method and consolidate them on a single class. No matter how we do it, we all end up with our goal which is to set up our desired capabilities. Every way works but I just want to share how I and others do it.

Desired Capabilities

The above image is how our JSON file will look like. It is an array of JSON objects. Each object has two keys, name and caps. The value of name will be used to identify which desired capabilities to use and that of the caps will be another JSON object containing the actual key/value pair of our desired capabilities.

Here are the steps we will do to read and set up the desired capabilities from a JSON file.

  1. Read and parse our JSON file.
  2. Get the value of caps based on the name.
  3. Convert the caps JSONObject to string then map it to a HashMap.
  4. We create DesiredCapabilities object using the HashMap.

Below are the codes implementing the steps above. I intentionally removed the exception handling and just throws an Exception in the method signature to simplify the methods. Your methods may look different if you decide to handle those exceptions.

Read and Parse JSON file

To parse our JSON, we will be using the JSONParser class provided by com.googlecode.json-simple. On how to add this to your project, just check their maven repository. The parse() method of the JSONParser can take an object of type Reader. From our Object Oriented concepts, we know the that FileReader is-a Reader, so we can pass an instance of the FileReader to the parse() method. The FileReader will take care of reading our JSON file, we just have to make sure to pass the correct path to the location of the file. The parse() method will do the parsing and will return the parsed value as an Object. Since we know the the content of the file is an array, we need to cast that Object into a JSONArray for us to be able to access its methods that we will use to work with our data. For exception handling purposes, take note the FileReader may throw FileNotFoundException, parse() method may throw IOException or ParseException.

Getting the value of caps based on the name

This is the getCapability() method. We pass the name of the capability we want to use and the location of our JSON file. A straight forward method. We used the parseJSON() method discussed above. We know that the file contains an array of objects, so all we need to do is iterate on each of those objects and see if the name matches the name of the capability we want to use. If it match, we get the value of caps and return it as JSONObject. One thing to note is, if the JSON is not an array of objects, say array of arrays. The cast to JSONObject will give us ClassCastException. So make sure that your JSON is formatted correctly like the image Desired Capabilities.

Converting the caps JSONObject to string and mapping it to a HashMap

Mapping the JSONObject to HashMap is very easy, thanks to the ObjectMapper available in Jackson Databind from com.fasterxml.jackson.core. To add this to your project, check their maven repository. First we create an instance of our ObjectMapper. Then we map the JSONObject to a HashMap using the readValue() method. If we look at ObjectMapper class, readValue() is a heavily overloaded method but we will use the readValue(String content,Class<T> valueType). content is the JSON value that we want to map to the HashMap. The getCapability() returns a JSONObject, so to meet the requirement of readValue() we converted it to a string. Note that getCapability() may return a null value and if it happens you’ll get a NullPointerException when calling toString(), it’s up to you to handle this exception. valueType is the class which you want to convert your JSONObject to. You can create your own class to model your JSON but in this case HashMap will do. Then we return the HashMap now containing our capabilities. Note that readValue() may throw JsonParseException or JsonMappingException and may even throw IOException in some unexpected cases.

Creating DesiredCapabilities object using the HashMap

This is now our public interface for getting the desired capabilities we want to use from our JSON file. We pass the name of the capability we want to use and the content root location of our JSON file. In the first line we are just constructing our path to the file. Fortunately we can construct a DesiredCapabilities object using a HashMap. So in the last line, we created and returned a new DesiredCapabilities object by passing the caps into its constructor.

Now you can use this getDesiredCapabilities() method to create your appium driver.

Or if you have read my How to Start Appium Server Programmatically in Java, you can use both of these to instantiate your appium driver.

Here is the complete code for our Capabilities Reader Class.

import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.io.FileReader;
import java.util.HashMap;

public class CapabilitiesReaderSimple {

private static JSONArray parseJSON(String jsonLocation) throws Exception {
JSONParser jsonParser = new JSONParser();
return (JSONArray) jsonParser.parse(new FileReader(jsonLocation));
}

private static JSONObject getCapability(String capabilityName, String jsonLocation) throws Exception {
JSONArray capabilitiesArray = parseJSON(jsonLocation);
for (Object jsonObj : capabilitiesArray) {
JSONObject capability = (JSONObject) jsonObj;
if (capability.get("name").toString().equalsIgnoreCase(capabilityName)) {
return (JSONObject) capability.get("caps");
}
}
return null;
}

private static HashMap<String, Object> convertCapsToHashMap(String capabilityName, String jsonLocation) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(getCapability(capabilityName, jsonLocation).toString(), HashMap.class);
}

public static DesiredCapabilities getDesiredCapabilities(String capabilityName, String capsContentRootLocation) throws Exception {
String jsonLocation = System.getProperty("user.dir") + "/" + capsContentRootLocation;
HashMap<String, Object> caps = convertCapsToHashMap(capabilityName, jsonLocation);
return new DesiredCapabilities(caps);
}
}

Why I like doing it this way is that it is easier for me to choose which device my test will run especially if i’m doing parallel test execution.

So there you have it. You’ve just got another idea on how to set up your desired capabilities. Again, there are many ways of doing things and yours may be better.

If you are new to mobile test automation and want to explore appium but haven’t set up your machine yet, check this How to Set Up Appium for Test Automation.

🍻 🍻 🍻

--

--

Rommel Malqued
Geek Culture

“Good Automation Brings Agility”. Software QA With An Agile Mindset. https://www.linkedin.com/in/rmalked/