UITest helper library for creating readable and maintainable tests

Overview

UITestHelper

Issues Documentation Stars Downloads

Version Language Platform License

Git Twitter LinkedIn Website eMail

General information

When creating UI tests you will see that you are often repeating the same pieces of code. The UITestHelper library will try to limit this code repetition. Besides that there is also functionality to make your code resistant against wrongly typed identifiers.

Using UITestHelper in your own App

'UITestHelper' is available through the dependency manager CocoaPods. You do have to use cocoapods version 1.1 or later

Below you can see a sample Podfile. You need to add the UITestHelper pod to your UI test target and if you want to use the GlobalHelper function you have to add the UITestHelper/App pod to your application target.

source 'https://github.com/CocoaPods/Specs.git'
use_frameworks!
workspace 'UITestHelper'

target 'UITestHelperApp' do
  platform :ios, '9.0'
  pod 'UITestHelper/App'
end

target 'UITestHelperUITests' do
    platform :ios, '9.0'
    pod 'UITestHelper'
end

# This will make sure your test project has ENABLE_BITCODE set to NO 
post_install do |installer|
    installer.pods_project.targets.each do |target|
        if ['UITestHelperUITests'].include? target.name
            target.build_configurations.each do |config|
                config.build_settings['ENABLE_BITCODE'] = 'NO'
            end
        end
    end
end

Instructions

Launching and connecting to your app with .tryLaunch

If you are using an XCode build server and run your tests in the simulator, then it can happen that you will not be able to connect to the simulator if your server is too bussy. For this the tryLaunch function has a build in retry mechanism. By default it will retry 10 times (can be changed by a parameter). After the tryLaunch all tests in your test class will have an app variable which point to the launched XCUIApplication.

The tryLaunch function also takes an array of RawRepresentable elements. Usually this will be an Enum that has a String as its base type. Your app will be launched with these parameters. In your app you can react on those parameters. In the case below you can see that the app is started with the MockNetworkResponses. Your app can then detect that value using the isLaunchedWith function and start the network Mocking.

    // In your XCTestCase class:
    override func setUp() {
        super.setUp()
        self.tryLaunch([LaunchArguments.MockNetworkResponses])
    }

    // Somewhere in your application (if you have added the UITestHelper/App pod)
    if isLaunchedWith(LaunchArguments.MockNetworkResponses) {
        // Start the network mocking
    }

Grouping your test statements

For getting a clear overvouw in your test output, you can group statements together. Groups can also be nested as far as you like. Starting a group is as easy as:

    group("Testing the switch") { activity in
        // Your test statements here will be grouped nicely in the test output.
    }

Taking screenshots

Screenshot will allways be added to an activity group. If you call the takeScreenshot function without parameter, then it will just create a default screenshot group. You can also specify a groupName for when it creates a new group. You can also give the screenshot any name.

    group("Testing the switch") { activity in
        takeScreenshot(activity: activity, "First screenshot")
        takeScreenshot()
        takeScreenshot(groupName: "Screenshot group?")
        takeScreenshot("Last screenshot")
    }

Using an enum for identifiers

UITestHelper has an extension for RawRepresentalbe so that you can directly get an XCElement from an enum value when you also have set that enum value as the accessibility identifier. For instance you can create a nested enum like this:

enum AccessibilityIdentifier {
    enum HomeScreen: String {
        case theLabel
        case theTextField
        case theButton
        case switch1
        case switch2
        case showButton
        case hideButton
    }
}

In your UIViewControllers you can then set those to the accessibility identifiers of your elements like this:

override func viewDidLoad() {
    super.viewDidLoad()
    theLabel ~~> AccessibilityIdentifier.HomeScreen.theLabel
    theTextField ~~> AccessibilityIdentifier.HomeScreen.theTextField
    theButton ~~> AccessibilityIdentifier.HomeScreen.theButton
    switch1 ~~> AccessibilityIdentifier.HomeScreen.switch1
    switch2 ~~> AccessibilityIdentifier.HomeScreen.switch2
    hideButton ~~> AccessibilityIdentifier.HomeScreen.hideButton
    showButton ~~> AccessibilityIdentifier.HomeScreen.showButton
}

Then In your tests you could use these like this:

func testEnumWithIdentifiersReusedForInteractingWithXCUIElement() {
    HomeScreen.showButton.tap()
    HomeScreen.hideButton.tap()
}

When identifiers are reused for instance when using a collection or table, then you can also enumerate your enum element.

    // pressing the last theButton
    let i = HomeScreen.theButton.count 
    HomeScreen.theButton[i - 1].tap()
}

You can then use all the functions below directly on the enum value

Waiting for an element

When creating tests you usually have to take into consideration if an element is accessible or not. For this various helper functions are created. app will be your launched XCUIApplication. By default this function will wait for a maximum of 10 seconds. This can be changed through a parameter. The waitUntilExists will return the element but it could still be unavailable (.exists = false). If you wan to to an Assert based on that existence. then you can use the .waitUntilExistsAssert function

    // Using the enum:
	XCTAssert(HomeScreen.theLabel.waitUntilExists().exists, "label should exist")
	HomeScreen.theLabel.waitUntilExistsAssert()
    // Or just accessing the elements the old fashioned way:
	app.buttons["Second"].waitUntilExists().tap()
	app.buttons["Button"].waitUntilExists(3).tap()

Select the element that does exists

With the .or function you can get one of the 2 elements that does exists. If both do not exists, then the first element will be returned and that .exists will be false. If you would like an assert in that case, then use the .orAssert function.

	HomeScreen.theLabel.or(HomeScreen.theTextfield).tap()
	HoeScreen.theLabel.orAssert(HomeScreen.theTextfield)

Conditional code based on existance

Execute some code if an element does exists. The default wait time is here also 10 seconds and can be set as a parameter.

	// Only execute the closure if the element is there.
	HomeScreen.theButton.ifExists { $0.tap() } // The button exist, so we do tap it
	HomeScreen.hideButton.ifExists(2) { $0.tap() } 

Execute some code if the element does not exists. The default wait time is here also 10 seconds and can be set as a parameter.

    // The button does not exist, so we don't tap it, we do something else
	app.alerts.buttons["Hide"].ifNotExist(2) {
		app.buttons["Third"].waitUntilExists().tap()
	}

Execute some code if the element does not exist and assume that after the code the element does exists. In the code below if the Hide button does not exist, then press the show button which will make the Hide button appear and then the hide button will be pressed.

	HomeScreen.hideButton.ifNotExistwaitUntilExists(2) {
		HomeScreen.showButton.waitUntilExists().tap()
	}.tap()
}

Enter field in a text field

Make sure the text field is ther, then tap on it and enter a text.

	HomeScreen.theTextField.tapAndType("testing")

Switching a switch on or of

No matter the current state of the switch, it will be switched to the specified state.

HomeScreen.switch1.setSwitch(false)

License

UITestHelper is available under the MIT 3 license. See the LICENSE file for more info.

My other libraries:

Also see my other public source iOS libraries:

  • EVReflection - Reflection based (Dictionary, CKRecord, JSON and XML) object mapping with extensions for Alamofire and Moya with RxSwift or ReactiveSwift
  • EVCloudKitDao - Simplified access to Apple's CloudKit
  • EVFaceTracker - Calculate the distance and angle of your device with regards to your face in order to simulate a 3D effect
  • EVURLCache - a NSURLCache subclass for handling all web requests that use NSURLReques
  • AlamofireOauth2 - A swift implementation of OAuth2 using Alamofire
  • EVWordPressAPI - Swift Implementation of the WordPress (Jetpack) API using AlamofireOauth2, AlomofireJsonToObjects and UITestHelper (work in progress)
  • PassportScanner - Scan the MRZ code of a passport and extract the firstname, lastname, passport number, nationality, date of birth, expiration date and personal numer.
  • AttributedTextView - Easiest way to create an attributed UITextView with support for multiple links (url, hashtags, mentions).
  • UITestHelper - UI test helper functions.
You might also like...
Trying to implement Unit Tests for @Binding properties in a ViewModel

BindingTester Trying to implement Unit Tests for @Binding properties in a ViewModel ViewModel to be tested class SheetViewModel: ObservableObject {

Catching fatal errors in unit tests

Precondition Catching When running tests which hit fatal errors, often preconditions the built-in support with XCTest. One package which supports cach

Write unit tests which test the layout of a view in multiple configurations
Write unit tests which test the layout of a view in multiple configurations

Overview This library enables you to write unit tests which test the layout of a view in multiple configurations. It tests the view with different dat

Bluepill is a reliable iOS testing tool that runs UI tests using multiple simulators on a single machine
Bluepill is a reliable iOS testing tool that runs UI tests using multiple simulators on a single machine

Bluepill is a tool to run iOS tests in parallel using multiple simulators. Motivation LinkedIn created Bluepill to run its large iOS test suite in a r

Swift framework containing a set of helpful XCTest extensions for writing UI automation tests
Swift framework containing a set of helpful XCTest extensions for writing UI automation tests

AutoMate • AppBuddy • Templates • ModelGenie AutoMate AutoMate is a Swift framework containing a set of helpful XCTest extensions for writing UI autom

Upload failing iOS snapshot tests cases to S3
Upload failing iOS snapshot tests cases to S3

Second Curtain If you're using the cool FBSnapshotTestCase to test your iOS view logic, awesome! Even better if you have continuous integration, like

Tool for generating Acceptance Tests in Xcode, inspired by Fitnesse
Tool for generating Acceptance Tests in Xcode, inspired by Fitnesse

AcceptanceMark is a tool for generating Acceptance Tests in Xcode, inspired by Fitnesse. Read this blog post for a full introduction to AcceptanceMark

A collection of useful test helpers designed to ease the burden of writing tests for iOS applications.
A collection of useful test helpers designed to ease the burden of writing tests for iOS applications.

MetovaTestKit is a collection of useful test helpers designed to ease the burden of writing tests for iOS applications. Requirements Installation Usag

Snapshot view unit tests for iOS

iOSSnapshotTestCase (previously FBSnapshotTestCase) What it does A "snapshot test case" takes a configured UIView or CALayer and uses the necessary UI

Comments
  • Reuse accessibility identifier to get XCUIElement

    Reuse accessibility identifier to get XCUIElement

    added an extension to RawRepresentable in order to reuse accessibility identifiers defined in a String enum to get the corresponding XCUIElement.

    Updated the Example project with a UITest showing how to use this way of writing a UITest. Bumped version in podspec to 1.4.0

    opened by smaljaar 8
  • Not require enum for tryLaunch

    Not require enum for tryLaunch

    Hi! Great job on this helper lib, looks promising to my intermitent failures on Travis. I have an issue tho with the tryLaunch requiring an enum to work. Firstly, if I don't need any custom launch args at all I still have to provide a populated non-optional array. Second, a UITest target cannot reference the application bundle, so this enum has to be replicated on each UITesting target AND the app (if I want to act on those values accordingly). It would suffice to make it an optional [String].

    opened by rafaelnobrepd 2
Releases(1.5.0)
Owner
Edwin Vermeer
Edwin Vermeer
An good example for UITest In swiftUI

SwiftUI_UITest A good example for UITest In swiftUI contains: UI test for swiftUI fake Web service for UI Test 'launch Environment' for use Fake Servi

hosein 2 Jan 12, 2022
Library for unifying the approach to network mocking in iOS unit- & UI-tests.

TinkoffMockStrapping Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements Installati

Online financial ecosystem 22 Jan 3, 2023
Small library to easily run your tests directly within a Playground

[] (https://developer.apple.com/swift/) Build Status Branch Status master develop About PlaygroundTDD enables you to use TDD directly on Xcode Playgro

Whiskerz AB 317 Nov 22, 2022
Freezer is a library that allows your Swift tests to travel through time by mocking NSDate class.

Freezer Freezer is a library that allows your Swift tests to travel through time by mocking NSDate class. Usage Once Freezer.start() has been invoked,

Sergey Petrov 8 Sep 24, 2022
Erik is an headless browser based on WebKit. An headless browser allow to run functional tests, to access and manipulate webpages using javascript.

Erik Erik is a headless browser based on WebKit and HTML parser Kanna. An headless browser allow to run functional tests, to access and manipulate web

Eric Marchand 544 Dec 30, 2022
TestSchedulerDemo - Demonstration code for iOS Unit Tests and Asynchronous

TestSchedulerDemo This repository contains demonstration code for my Medium arti

Carsten Wenderdel 0 Mar 19, 2022
Marvel - Marvel Characters App using MVVM, and including unit tests

Marvel About The purpose of this project is to develop a app using MVVM, and inc

null 1 Mar 20, 2022
Detailed explanations and implementations of various maths concepts for writing high performance code/algorithms backed with Unit tests.

Detailed explanations and implementations of various maths concepts which can help software Engineers write high performance code/algorithms backed with Unit tests.

Mussa Charles 2 Sep 25, 2022
Mockit is a Tasty mocking framework for unit tests in Swift 5.0

Mockit Introduction Mockit is a Tasty mocking framework for unit tests in Swift 5.0. It's at an early stage of development, but its current features a

Syed Sabir Salman-Al-Musawi 118 Oct 17, 2022
Swift Package with examples of how to tests iOS apps

GimmeTheCodeTDD A swift package with examples of unit tests in iOS development. Requirements Xcode 13 Content Dependency Injection Constructor Injecti

Dominik Hauser 8 Oct 11, 2021