Framework Structure

Introduction

It is in this part of the series that  you will start actually writing code.  If you are somewhat new to coding in Java, I recommend writing out all the code snippets from scratch rather than copying and pasting them, for some of the following reasons;

  • As you start writing code, you will start picking up on patterns in the code, which will help you pick up things quicker
  • As you write out the code and try to reference certain libraries, IntelliJ will auto-suggest references to import for you, which will also help you learn the code that you are writing ?

Starting Appium Server Programatically

Because we installed Appium Server globally to our system, it has been added to our PATH and thus, we are able to start and stop the Appium Server programatically in Java using ‘AppiumDriverLocalService’. Let’s set this up now 😀

  1. With the project open in IntelliJ, right-click on the ‘utils.appium’ package and select ‘New’ -> ‘Java Class’
  2. Name the class ‘AppiumServer’ and click OK
  3. Add the following ‘private static AppiumDriverLocalService’ variable in the class and also add two static methods to start and stop the Appium Server respectively, the whole thing should look like below…

utils.drivers package

Editing the ‘IOSAppDriver’ Class

Appium has come a long way over the years and made it a lot easier to connect to the devices we want to connect to.  Because we will be specifying that we are using IOSDriver, which is of course specific to the IOS platform, we do not need to declare the ‘platformName’ in our Desired Capabilities. If we instead used the more general parent class of AppiumDriver that IOSDriver inherits from, then it would need the ‘platformName’ defined in the Desired Capabilities to distinguish between iOS and Android.

All we really need to set in our DesiredCapabilities is the ‘deviceName’ (of the iOS Simulator), the ‘platformVersion’ (e.g. the OS like 11.4),the ‘automationName’ (e.g. ‘XCUITest’ for iOS) and the app we want to test.  A full list of Desired Capabilities can be found at http://appium.io/docs/en/writing-running-appium/caps/

In this blog series, we will automate the sample Artistry app provided in the Swift-30-Projects repo which can be found at https://github.com/soapyigu/Swift-30-Projects

  1. Go to https://github.com/soapyigu/Swift-30-Projects and git clone the repo to a local folder on your machine…
    • Open up Terminal
    • Install Git if not installed already…  brew install git
    • Change directory (cd) into a folder you want to clone the ‘Swift-30-Projects’ repository into…  cd path/To/LocalFolder
    • Git clone the repository…  git clone https://github.com/soapyigu/Swift-30-Projects.git
  2. Open the local repository folder and then open the ‘/Project 05 – Artistry’ directory and launch the ‘Artistry.xcodeproj’ in Xcode
    • Right-click on the Artistry.app file in the Products folder in the  Project explorer pane, and select ‘Show in Finder’
    • Copy the app into the /src/ folder of your Java (IntelliJ) project

Next let’s setup our IOSDriver 🙂

  1. In the project open in IntelliJ, edit the ‘IOSAppDriver’ class file so it looks similar to below…

In the above, we create a loadIOSDriver() method which returns IOSDriver.

We then start up the Appium Server.

Then, we set the filepath of the .app file to install on the device.

Next, we set the DesiredCapabilities that we want in our Appium session when we load this Android Driver…

  • platformVersion – iOS version of our device simulator
  • deviceName – name of our device simulator
  • automationName – automation engine to use
  • app – filepath to the APK file we want to use

We finally set our IOSDriver to an Appium session with the specified DesiredCapabilities and then return the driver to be used.

utils.appium package

Editing the ‘DriverController’ Class

  1. Open up the ‘DriverController’ class in the ‘utils.appium’ package and edit the class file to match below, to create an instance of DriverController which can be used to start the IOSDriver and device (we have also used Log4J2 here to report any errors when stopping the Driver)…

Editing the ‘Driver’ Class

  1. Open up the ‘Driver’ class in the ‘utils.appium’ package and edit the class file to match below, to create a public IOSDriver instance which returns an instance of DriverController when initiated, which can then be used in test methods (e.g. finding elements or implicitly waiting etc)…

Editing the ‘Settings’ Class

  1. In our framework, we use the Settings file to store public static variables that we will want to be using in our project.  In this blog series, we will make a simple automated test that navigates through some screens and that is really it.  This test currently does not require us to store anything in our Settings class, so we can leave it empty for now, it’s just good to know what it would be used for, e.g. storing sensitive data like login credentials (or environment variable names to where the credentials are stored).

utils.hooks package

For now, we will only be adding Before and After hooks for the top-level Cucumber scenarios/feature files.

Editing the ‘CucumberHooks’ Class

  1. Open up the ‘CucumberHooks’ class in the ‘utils.hooks’ package and edit the class file to match below.  This class file will contain all our Before and After hooks for our Cucumber scenarios, which respectively get executed before or after a Cucumber feature and/or scenario. Please see https://github.com/cucumber/cucumber/wiki/Hooks for more information…

pages package

Editing the ‘BasePage’ Class

  1. Open up the ‘BasePage’ class in the ‘pages’ package and edit the class file to match below.  The ‘BasePage’ class is where we will later put all our test methods for our BaseScenarios, and any methods that exist / can be shared across more than one specific page object (e.g. main navigation, validate a passed pageUrl etc)…
    (Also note we threw in a Log4J Logger for the class so we can use methods like log.debug() instead of using System.out.println() to print out information) 🙂

Editing the ‘Page’ Class

If you’ve followed my Java Web Selenium or Appium Mobile Web blog series, you will notice that in our ‘Page’ class, we created a generic method called instanceOf() that takes the same generic class and initialises a new object from PageFactory with all the correct elements for the page initialised. It looked similar to below…

This works perfectly fine if we only use Selenium’s @FindBy annotations and WebElement class.  However, when we want to use annotations or element classes specific to mobile / Appium, it is required to decorate our driver instance with an AppiumFieldDecorator. If we look at Selenium’s PageFactory class, we can see that it contains the following methods…

If we examine the above PageFactory class carefully, we can see that unfortunately, there is no initElements() method which takes both a FieldDecorator and a generic class.

This is slightly problematic as we want to implement PageFactory using our instanceOf() method which takes a generic class that we pass into it as our page class, as well as be able to use the required AppiumFieldDecorator, instead of implementing PageFactory the traditional way where we initElements() in the constructor of each page class (in this case we would just pass in the page class and wouldn’t need a generic).

To solve this without resorting to the traditional implementation of PageFactory where we call initElement in each page classes constructor, and be able to use both a generic class with AppiumFieldDecorator, we can create our own initElements() method which first instantiates the generic class as a page class and then passes that in to the AppiumFieldDecorator overloaded initElements() method. Note that we’ve had to copy the instantiatePage() method from Selenium’s PageFactory class, due to the fact they made it private 🙁

  1. Open up the ‘Page’ class in the ‘pages’ package and edit the class file to match below…

Step Definitions

Editing the ‘BaseSteps’ Class

  1. Open up the ‘BaseSteps’ class in the ‘steps’ package and edit it to match as below. This is just a placeholder step definition that inherits from ‘Page’ class, to help follow POM concepts…

Editing all the other Step Definitions

  1. Open up every other Step Definitions class file and change the classes so that they all inherit/extend from the ‘BaseSteps’ class (and thus in turn, inherit from the ‘Page’ class). Please find one example below…

TestNG

With TestNG, a TestRunner class can be made which defines everything that you want to happen to that group of tests. To work with Cucumber, you must define the directory where your Feature files are located in the project, as well as define where the glue is that connects your Feature files to your java test methods (both hooks and step definitions). The TestRunner class can also define what happens before, after and during the tests are run.

Creating the ‘TestRunner’ Class

  1. Right-click the src/test/java directory, select ‘New’ –> ‘Java Class’ and name the class “TestRunner”
  2. Add the following lines of code in to the ‘TestRunner’ class (also note the @CucumberOptions, where the location of the feature files, glue files and any formatter plugins are defined)…

    Interestingly, you can actually make as many TestRunner classes as you see fit for your project and then define which TestRunner classes, if any, get run within a test suite.  You define all of this within a file called ‘testng.xml’.

Creating the ‘testng.xml’ File

  1. Right-click the project root in the Project Explorer, select ‘New’ –> ‘File’ and create a file called ‘testng.xml’ and press the ‘OK’ button
  2. Open up the ‘testng.xml’ file and add the following lines of XML into the file (using similar/appropriate names for your own test suite and test name)…

Building the Project

Building the Maven project

  1. Open CMD-prompt / Terminal and cd (change directory) into the root of your Maven project. For example…
    cd /Users/username/DevProjects/ProductAutomationFramework
  2. Enter the following command to build your Maven project…
    mvn clean install -DskipTests  (we currently have no tests. If we don’t put in the skipTests command, we will get a build error around one of the cucumber report plugins we are using).

Building the Gradle project

If you have instead setup the project with Gradle instead of Maven, you can follow the steps below to build…

  1. Open CMD-prompt / Terminal and cd (change directory) into the root of your Maven project. For example…
    cd /Users/username/DevProjects/ProductAutomationFramework
  2. Enter the following command to build your Maven project…
    ./gradlew build

Our core framework is now setup, in the next part, we will begin adding our test scenario 😀

Digiprove sealCopyright secured by Digiprove © 2018
Liked it? Take a second to support Thomas on Patreon!

Leave a Reply

Your email address will not be published. Required fields are marked *

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