Appium — Mobile App Automation| Android/iOS application automation with POM, Cucumber BDD | Part II

Ekrem Kurt
11 min readJun 10, 2021

--

In the following article, as promised I will focus on how to build one framework, including Cucumber, POM, and of course Appium. The programming language will be Java. As a build management tool maven, and as framework both JUnit and TestNG frameworks will be used. It will work both on Android & iOS devices, and also it is compatible to work on both macOS and windows. However, if the tests need to run also on iOS devices, it is highly encouraged to use macOS.

This article targets mainly those, who have already knowledge of basic programming language (preferably OOP), at least have an idea how Appium works, and feel comfortable with basic testing concepts and testing framework, since such details will not be covered. If you want to review the concept of the Appium please refer to this link. There will be of course some prerequisites to start with :) Lets start!

Prerequisities:

Type following command in terminal to install

$ xcode-select --install
  • Install Carthage. (In case you don’t have any idea what does that mean, please refer to link and read the instructions)

First, change the permissions and accept the Xcode license as shown below commands.

$ sudo chown -R $(whoami) /usr/local/share/man/man5 /usr/local/share/man/man7
$ sudo xcodebuild -license accept

Then, install Carthage by typing following command in terminal.

$ brew install carthage

Type following command in terminal to install node.

$ brew install node

Now we can check the value of the JAVA_HOME variable.

echo $JAVA_HOME

The result should be the path to the JDK installation. Do the same steps for the value of the ANDROID_HOME variable.

/Library/Java/JavaVirtualMachines/jdk-15.0.1.jdk/Contents/Home
  • Run following command in terminal to install appium-doctor.
$ npm install -g appium-doctor

There are some more additional nice to have tools such as Webpack, libimobiledevice, ios-deploy, Cmake, Opencv4nodejs, Applesimutils, ios-webkit-debug-proxy, osxfuse, ifuse, ffmpeg, set-simulator-location, fb-idb available— these tools can also be seen after running appium-doctor command.

Now, you are good to Start the scripting 😃

Structure

The Page Object Model is one of the best approaches to testing that QA engineers can apply to a test automation project. It is such a way of structuring the code in an automation project that improves code quality and readability, test maintenance, and above all, it is a great way of avoiding complexity. The main advantage of Page Object Model is that if the UI or any HTML object changes for any page, the test does not need any fix. Only the code within the page objects will be impacted, but it does not have any impact to the test. The basic idea behind it comes to keeping all references to mobile elements and methods in one class file for each page or screen of the app (or web page for non-native web applications).

* Sample project structure

As you can see above, it is one example of framework structure. All the files related to test activities belong to test folder, and all the files related to configuration and setups are under the main folder. In that way, it is easy to manage once the project gets bigger in the time.

Additionally, while creating your pages and step definition class files, it is advised to choose names that are related to the page (app screen) which contents you are going to work on. Adopting the page naming convention ensures that anyone involved in the project can get familiar with it straight away and start collaboration on it in no time.

* Initialize PageFactory Elements

Another ingredient expanding the benefits of the Page Object Model in the test automation project is PageFactory. It is a tool that helps you reduce the coding work and easily put MobileElements locators in code, using @FindBy notation. As the name suggest, it helps to find the elements in the page using By strategy. From there, finding elements for Appium to interact with them in tests is much simpler. It is also not limited to only className, Id, accessibilityId or Xpath, there are some additional locator strategies spesific to Appium available.

* PageFactory in use

All methods need to be written also including both platform. With that approach it is very simple to execute tests either on Android devices, or any kind of iOS devices. You don’t need to prepare one separate framework for iOS, after preparing one for Android. There are some slightly changes which can be found on the official document such as using getAttribute Method- to get the text of the element for instance we should use text attribute for Android, and label attribute for iOS.

Importance of the Encapsulation in the Framework

As already can be seen above, all mobile elements in the class are defined private. In some cases it is needed to make it protected, so that it can be also reachable from the sub-classes. However, the best practice is to make them private as much as possible and writing public methods inside the page classes to use private variables.

* An example public method using private variable in the same class

Instead of defining all the desired capabilities statically in the classes, it is again best practice to use also encapsulation concept.

We are suing ThreadLocal Class to define our parameters, so that we can run them in parallel and cross-platform. After defining all the parameters, we should initialize them.

* Initialize Global parameters

It is initially set to Android Device, by defining platformName, udid, and deviceName as an Android. We can just adjust it by changing the parameters. We are not limited to emulators and simulators only, by defining real device parameters we can also run tests on real devices.

* setting parameters for iOS device

Now we are ready to set our capabilities via Capability manager.

Understanding the steps

Another aspect of setting up this kind of project comes down to taking advantage of Cucumber and using Gherkin language. Gherkin implements a straightforward approach with Given, When, Then notation with the help of the additional And and But which seems fairly easy to use. You could write pretty much anything you want in the test steps of your feature files. Ultimately, the called methods are going to perform actions.

* Test scenario written in Gherkin language

But the reason for using the Behavior Driven Development approach and Cucumber itself is enabling the non-tech people involved in the project to understand what is going on in the tests field.

We should try to write steps as general as possible and possibly using parameters to cover all similar steps, so that we don’t need to write the step definition each time. As seen above, even I click “Cancel” button or another types of button, I always use the same step by only changing the parameter. The same also applies for “Given I’m on the “Searches” page”, and “Then I should land the “Searches” page” steps. When the project gets bigger, that kind of approach will be very helpful to save the time.

Now, we are going one step further into the step definitions class to define our steps, which are written in features file. Instead of writing the whole testing logic inside the step definitions, it is good to handle all these in page classes and directly implement them in step definitions with the help of OOP concept.

* Step definition of one step

Next step is to define a method, in this case “swipeLeftToDelete” method, which is defined in the respective page class.

Finally, to define the “swipe” method itself, either in the utilities class or in the basepage (depending on the project), in order to reuse it whenever it is needed.

Executing tests

Of course, we need one runner class in order to execute our test cases. If we just say run, then the tests will be executed on the selected/initiliazed device, which was defined in GlobalParams Class.

* Runner class

As it can be seen, even though it is very useful at the beginning of the project to analyze after writing a test and directly see the result by just running on IDE, it is not so practical to go “GlobalParams Class” each time to change parameters, if we want to execute tests on different platforms. With the help of JUnit and Maven, we can execute our tests from the command line, just by changing the related parameter. Another biggest advantage of course to be able to integrate it with CI/CD tools, just providing one specific line.

* Different types of examples to execute tests from the command line with the help of maven. The parameters are interchangeable.

So far, we have covered to run on Android Emulator or any type of iOS simulator. To execute tests on any real Android device is very simple. We just need to connect our phone to computer via USB cable or via Wi-Fi, then the whole above-mentioned steps can be applied to real device. There is no difference at all! For the small adjustments please refer to this document.

In order to test it on real iOS devices, a valid iOS Development Certificate and Provisioning Profile are necessary. Your app will also need to be signed. More Information can be found about this in the Apple documentation.

Parallel execution on multiple Android and iOS devices

There are two options available to run the tests parallel, one with the help of JUnit, and another with TestNG. As all we know, JUnit has limitations, regarding parallel testing. In JUnit, the feature files are run in parallel rather than scenarios, which means all the scenarios in a feature file will be executed by the same thread. Either Maven Surefire or Failsafe plugin can be used to execute the runners. In TestNG the scenarios and rows in a scenario outline can be executed in multiple threads. Even though to choose the right option is project dependent and cucumber is mainly used with JUnit, I would personally prefer TestNG option to be more flexible. To combine the cucumber project with TestNG there are also more than one way. The first one is to follow the cucumber documentation. Another way is to create separate runner files for the devices that we want to run parallel and define them in the testng.xml file, instead of inheriting from AbstractTestNGCucumberTests.

* testng.xml file to define Desired Capabilities of each device

As I said we can define as much device as possible based on our needs to run tests parallel and cross-functional. After defining inside testng.xml file we just need to create seperate runner files.

For the common steps one “RunnerBase” class can be created, and all other runner files can extend it.

Another concern regarding mobile testing is also using hooks. If we are testing web application using selenium or any other automation tool, it is common approach to open and close the browser inside the hooks class. That means, before each scenario browser opens, execute the test and then browser is closed. With the second scenario the browser opens again and the process is the same. However, in mobile testing launching the application time is between 15–30 seconds, depending on many factor. If we have just a few scenario, then it is not a problem. But having more than 100 scenarios and closing the application each time and with the new scenario launching it again is a bit challenge and time consuming. To overcome this issue, there is also one way to put all those steps, which are in Hooks class, inside runner class. With the help of JUint @BeforeClass and @AfterClass anotations.

Generally, tests should be designed not to depend on each other. This is certainly not a law, but a good practice, because it gives your test suite a number of nice properties — With independent tests, you can add tests at any place, delete tests, re-order tests without unexpected impacts on other tests. Every test can be understood without looking at other tests, and in case of failing tests the reason for the failure is easier to find. Independent tests succeed and fail individually. With dependent tests, if one test fails, subsequent tests likely also fail.

Keeping those principles in mind, the project should be designed from the beginning, and feature files should be organised properly in a such a way, so that we can reduce dependency between tests, if we want to use this approach. It is also again project dependant — for instance I have used this approach with one project, and it was not suitable for the another one. If the project is not suitable, just define above defined lines inside hooks. The rest will be the same.

After defining testng.xml file and creating respective runner files, we can now execute it by just runnig “mvn test” command. It produces separate reports as well for each device.

We can get a beautifull detailed report for each device separetely after executing our tests parallel.

* A sample cucumber report.

Summary

As it can be seen, the concept of best practices in automation testing can be summarized in three words: reusability, maintainability, and performance. Reusability means fewer coding, consequently diminishing the time needed to finish the job. If the code is un-readable it’s useless, no matter how fast it is. And it definitely won’t be be re-used. Finally, performance saves execution time and improves stability. All three contributing not only to the quality of the test automation project but have a significant role in enhancing the overall quality of the delivered app.

In the following article, I will try to cover different types of reportings, how to run appium server systematically, how to run emulators/simulators programatically, and small tricks on how to use appium desktop to find locators.

Sources:

--

--

Ekrem Kurt
Ekrem Kurt

Written by Ekrem Kurt

Technology fancier & Quality assurance provider & Blockchain enthusiast.

Responses (1)