Skip to main content
XCUITest Framework
Doris Sooläte avatar
Written by Doris Sooläte
Updated over a year ago

The Structure follows the MVVM pattern, where we have four layers in the framework

  • Helpers

  • Screens

  • Tests

Tools needed to be installed on the machine

  • XCode

  • Xcode command line tools

Setting up the framework

  • Clone the repo

  • Checkout XCUITest branch

  • Open the project in Xcode

  • Xcode will take some time to install all dependencies

Understanding framework components

  • ToDoListUITest group contains our base framework

  • TestCases group will contains all Test class and each test class inherits the BaseTest class, which having hooks to manage the state

  • BaseTest class is in Base group

  • `Screens` group contains all screen classed which is mapped individual screen on the app, each screen class inherit BaseScreen class, which provide access for screen related common methods

  • BaseScreen is present in Base group

  • We have different `Helpers` classes in `Helpers` group for each specific type of action given below

  • We have `ActionHelper` class having methods used device related actions

  • There is `AppHelper` class having methods to deal with app

  • ElementHelper class is having methods meant to work on elements

  • `AlertHelper` class contains methods for working with Alerts

  • `ScreenShotHelper` has method to take screenshot

  • Then we have `Logger` group containing `LogInfo` class to deal with logging

  • Locators groups contains locators for different screen as json files

Getting locators for app

Though Xcode has an Accessibility inspector which can be opened via XCode > Open developer tools > Accessibility Inspector, but it is annoying and not accurate. So, we will follow different method here is a bit manual, mentioned below

  • Setup a debug point in a test just after launch

  • From Product menu run `Test`, at debug point shell interface appears, now type the command `po app.debugDescription` and hit enter, page element hierarchy be print on console

  • Suppose you want to print only, button elements on the current screen, then execute `po app.buttons`, similarly specific elements can be found

  • Similarly you element with attribute and attribute value

  • Now, we are using predicate queries for getting the element, as predicate queries are most fastest and accurate way to locate the element

  • Each screen is having its own locator<Screen-Name>.json file in Locators group for example

 {
"page": "loginScreen",
"locators": [
{
"elementId": "continueButton",
"by": "predicate",
"elementType": "Button",
"query": "label == 'Continue'"
},
{
"elementId": "gotItButton",
"by": "predicate",
"elementType": "Button",
"query": "label == 'Activate'"
}
]
}
  • Where `page` key having screen name as value while `locators` contains all locators

  • Each locators will be like in the format

     {
    "elementId": "gotItButton",
    "by": "predicate",
    "elementType": "Button",
    "query": "label == 'Activate'"
    }

  • Where query is predicate string

    Writing Screen classes

  • Each screen on app will have a corresponding screen class in project, which will inherit base class

  • Locators will be defined like this
    lazy var continueButton: XCUIElement = elementProvider.getElement(elementType: LoginScreen.locatorMap.getElementType(key: "contButton"), value: LoginScreen.locatorMap.getElementQuery(key: "contButton"));
    Where `locatorMap` map will be having element type and predicate string (as mentioned in json file)

  • Then, we will have method for operation on that element

    func tapOnCaontinueButton() {
    lUtil.printLog(message: "Clicking Continue button");
    XCTContext.runActivity(named: "Clicking continue button") {
    _ in
    continueButton.tap();
    }
    }


    XCTContext.runActivity method creates a granular log in xctest result

Writing Test Classes

  • Test class are consists of test methods, which can be sequentially executed, executed independently, based on before and after hooks logic

func testExample2() throws {
let loginScreen: LoginScreen = LoginScreen();
XCTContext.runActivity(named: "klllmllllllllllllGBHHH") {
_ in
loginScreen.tapOnCaontinueButton();
}
}
  • In test class we need to initialize the screen classes, execute the methods and make assertions

Test Case Execution

  • First way is to via IDE

    • First we need to select Target as ToDoListUITests, then simulator or physical from adjacent dropdown

    • Then, from product menu, select Test menu item

  • Second method, we recommend is, via command line

    • To execute all test in ToDoListUITest scheme, run command

      xcodebuild test -project ToDoList.xcodeproj -scheme ToDoListUITests -destination 'platform=iOS Simulator,name=iPhone 15'
    • To run specific test class, run command

      xcodebuild test -project ToDoList.xcodeproj -scheme ToDoListUITests -destination 'platform=iOS Simulator,name=iPhone 15'  -only-testing:TargetName/TestClass

      For example:

      xcodebuild test -project ToDoList.xcodeproj -scheme ToDoListUITests -destination 'platform=iOS Simulator,name=iPhone 15'  -only-testing:ToDoListUITests/ToDoListUITests

    • To run specific test method in class

      xcodebuild test -project ToDoList.xcodeproj -scheme ToDoListUITests -destination 'platform=iOS Simulator,name=iPhone 15'  -only-testing:TargetName/TestClass/TestMethod

      For example:

      xcodebuild test -project ToDoList.xcodeproj -scheme ToDoListUITests -destination 'platform=iOS Simulator,name=iPhone 15'  -only-testing:ToDoListUITests/ToDoListUITests/TestExample

Did this answer your question?