Running same tests on both android and iOS devices

I want to run the same set of tests on both android and iOS devices.

So, for each device I have a different set of objects. Is there a way to run the same set of tests on each device without having to have a separate set of tests and objects.

Is there like a translation layer that would select the right set of objects depending on if Android or iOS device was selected?

Hi Jon, I just started doing this for my project! I’m sharing the same test file across iOS and Android. I am dynamically switching the app file based on the deviceOS. I also created a set of Test Objects for each platform with the same names, in separate Object Repositories

First, for the appFile, I created a reusable function (ended up making it a Custom Keyword later):

def startApp(String iOSFile, String androidFile, boolean resetSimulator = false) {	def deviceOS = RunConfiguration.getExecutionProperties().drivers.system.Mobile.deviceOS	def appFile = deviceOS == 'iOS' ? iOSFile : androidFile 	Mobile.startApplication(appFile, resetSimulator)}

I’ll pass both the iOS and Android file locations to this function when I start up my test, and let the deviceOS determine which to load.

In my test, when I’m looking for an object, I created a reusable findObject function which will pull from the correct Object Repository (“iOS Test” or “Android Test”). I also broke down the test objects into “Tabs”, “Buttons”, “Labels”, “Text Fields” types.

TestObject findObject(String type, String name) {	def deviceOS = RunConfiguration.getExecutionProperties().drivers.system.Mobile.deviceOS	String objectRepo = deviceOS + ' Test'	type = type ? type + '/' : ''		String object = objectRepo + '/' + type + name	return findTestObject(object)}

Finally, because the functionality of my iOS and Android apps aren’t exactly the same, I have some branching logic that I can use to determine which code to run. I did this as a Custom Keyword:

package com.my.keywordsimport com.kms.katalon.core.annotation.Keywordimport com.kms.katalon.core.configuration.RunConfigurationimport com.kms.katalon.core.mobile.keyword.MobileBuiltInKeywords as Mobilepublic class system {	@Keyword	boolean isIOS() {		return 'ios' == RunConfiguration.getExecutionProperties().drivers.system.Mobile.deviceOS.toLowerCase()	}	@Keyword	boolean isAndroid() {		return 'android' == RunConfiguration.getExecutionProperties().drivers.system.Mobile.deviceOS.toLowerCase()	}	}

Then in my test, I can check:

if (CustomKeywords.'com.my.keywords.system.isIOS'()) {
// Do iOS things
} else {
// Do Android things
}

Hope this helps!

1 Like

Chris Trevarthen said:

Hi Jon, I just started doing this for my project! I’m sharing the same test file across iOS and Android. I am dynamically switching the app file based on the deviceOS. I also created a set of Test Objects for each platform with the same names, in separate Object Repositories

First, for the appFile, I created a reusable function (ended up making it a Custom Keyword later):

def startApp(String iOSFile, String androidFile, boolean resetSimulator = false) {	def deviceOS = RunConfiguration.getExecutionProperties().drivers.system.Mobile.deviceOS	def appFile = deviceOS == 'iOS' ? iOSFile : androidFile 	Mobile.startApplication(appFile, resetSimulator)}

  
I'll pass both the iOS and Android file locations to this function when I start up my test, and let the deviceOS determine which to load.  
  
In my test, when I'm looking for an object, I created a reusable findObject function which will pull from the correct Object Repository ("iOS Test" or "Android Test"). I also broke down the test objects into "Tabs", "Buttons", "Labels", "Text Fields" types.  
  

TestObject findObject(String type, String name) { def deviceOS = RunConfiguration.getExecutionProperties().drivers.system.Mobile.deviceOS String objectRepo = deviceOS + ’ Test’ type = type ? type + ‘/’ : ‘’ String object = objectRepo + ‘/’ + type + name return findTestObject(object)}


  
  
Finally, because the functionality of my iOS and Android apps aren't exactly the same, I have some branching logic that I can use to determine which code to run. I did this as a Custom Keyword:  
  

package com.my.keywordsimport com.kms.katalon.core.annotation.Keywordimport com.kms.katalon.core.configuration.RunConfigurationimport com.kms.katalon.core.mobile.keyword.MobileBuiltInKeywords as Mobilepublic class system { @Keyword boolean isIOS() { return ‘ios’ == RunConfiguration.getExecutionProperties().drivers.system.Mobile.deviceOS.toLowerCase() } @Keyword boolean isAndroid() { return ‘android’ == RunConfiguration.getExecutionProperties().drivers.system.Mobile.deviceOS.toLowerCase() } }


  
Then in my test, I can check:  
  
  
  
  
  
  
  
  
  

if (CustomKeywords.‘com.my.keywords.system.isIOS’()) {
// Do iOS things
} else {
// Do Android things
}


  
  
Hope this helps!

  

Thanks Chris, your answer is very much appreciated. However, I am quite new to this and so this feels a little complicated to setup. Was hoping there was a simply option via the Katalon UI :frowning:

Hi Chris,

Thanks a lot for sharing this.
Can you please let me know where you are creating findObject function, I really need help in this.
I am working on a project which has similar app for android and iOS, I need to combine both so that I can run single set of test on both platforms.

Hi Sameer,

When I first wrote the above code, I was putting that findObject function in my Test Case. As I started to make more tests, I realized that wasn’t very efficient. After some time, I started to write an external library that I could use in my tests as reusable code. It’s open source and available here:

You can grab the prebuilt .jar file and put it in your test’s Drivers folder in order to use it:

https://github.com/detroit-labs/katalon-mobile-util/releases/download/1.7.0/katalon-mobile-util-1.7.0.jar

More info on how to include external libraries can be found in Katalon’s docs:

In the utility library, there is a section on finding TestObjects specifically, which switches between iOS and Android for you based on the device:

Hope this helps,

Chris

1 Like

Hi Chris,

We have used the above library provided by you and it works great for some simple pages.
But we have store objects in the below mention way : ```
TestObject alert = Finder.findAlert(‘My Alert’)
TestObject button = Finder.findButton(‘My Button’)
TestObject checkbox = Finder.findCheckbox(‘My Checkbox’)

Do you have a reference project , where you have utilized all these and have created a modular structure.
It would help me a lot.

Thanks in advance

Hi @Sameer_Singh,

I’m glad you’re finding some use from the library! I don’t have a reference app of my own that I’m able to share - but that’s a good idea. I might be able to use the Sample Test project that comes with Katalon Studio as a basis for one. It’ll take a little time, so I’ll have to get back to you.

In the meantime, if you have any specific questions about how to use anything, please let me know.

– Chris

Thanks a lot for quick reply @Chris_Trevarthen
There are few queries I would like to ask:

  1. On every page we have to define the Objects in accordance with the method suggested by you. Like : TestObject alert = Finder.findAlert(‘My Alert’)
    TestObject button = Finder.findButton(‘My Button’)
    Is is possible that we can define them in Object Repository or use Page Object Model and define them in some other method and then use them.

  2. As per my understanding of the documentation, the driver will have to determine the OS on each page of the Application(I might be wrong), is there a better way to handle this.

I will get back to you with few more queries(please bear with me).

Thanks,
Sameer

Maybe my responses here will help?

Hi @Sameer_Singh,

On every page we have to define the Objects in accordance with the method suggested by you. Like : TestObject alert = Finder.findAlert(‘My Alert’)
TestObject button = Finder.findButton(‘My Button’)
Is is possible that we can define them in Object Repository or use Page Object Model and define them in some other method and then use them.

You can definitely create the TestObjects in the Object Repository. The code you listed above is how you would refer to them in your test code itself using the name, e.g. “My Button”, that you gave to that Test Object when you captured it.

In this example below, I captured both iOS and Android checkbox objects and named them “Create account checkbox” and “Menu item checkbox”, storing them in the appropriate folders.

When I want to access one of them, I use TestObject createAccountCheckbox = Finder.findCheckbox('Create account checkbox'). The Finder class will check which platform the tests are running on and will grab the appropriate Test Object for that platform so that we can use it in our test like Mobile.tap(createAccountCheckbox).

The Finder class offers a more convenient way (in my admittedly biased opinion) to get objects from the Object Repository without having to always type the full path to the object or create a bunch of if statements to determine which platform the tests are running on.

Note that you only need to use the Finder.findCheckbox() function once for each checkbox, button, etc. in a given test - once you define it in one Test Case file, you can re-use it. If you’re interacting with the same Test Objects in multiple tests, then you would need to repeat the Finder line in each Test Case. You might be able to create a Custom Keyword for frequently used Test Objects, but that might be just as much typing/code.

  1. As per my understanding of the documentation, the driver will have to determine the OS on each page of the Application(I might be wrong), is there a better way to handle this.

The Finder class actually checks the device OS every time your test code looks up an object but this is all done behind the scenes and you don’t have to do anything special other that making sure you put your Test Objects in the appropriate folders of the Object Repository.

I hope this clears some things up, but let me know if you have other questions,

Chris

@Chris_Trevarthen, thanks a lot for your help. Your approach is very helpful. However I have a question: what is the best way to define DeviceOS and Platform when using Kobiton?

Hi @mr_crank,

If you’re using katalon-mobile-util, and the device OS and platform are not being automatically chosen (which might be the case with Kobiton), you can use version 1.13.2 for katalon-mobile-util, which will allow you to specify those values in your test instead of autodetecting:

It adds the ability to set the platform you’ll be testing on:

import com.detroitlabs.katalonmobileutil.testobject.Finder
import com.detroitlabs.katalonmobileutil.device.Platform

Finder.setPlatform(Platform.ANDROID)
// or Finder.setPlatform(Platform.IOS)
// or Finder.setPlatform(Platform.WEB)

This will make Finder look in Object Repository/Android Objects/ for your Test Objects (or the other platform directories as specified).

Hope this helps,

Chris

I am using katalon-mobile-util with browserStack and I have a NullPointerException:

Part of the code:


Could you have an idea please ? Thanks