UITestCase Automation Testing with Xcode

UITestCase using Xcode


TestCases for UI helps to automate the testing. In case of iOS , it is subclass of XCTestCase , which is part of XCTest framework.

The subclassed object can be usually considered a Test Suite. A Test Suite is nothing but a group of similar test classes intended to test a specific behavior.

To understand more about the automation testing using Xcode , we will consider a simple example which will test the alert message being shown appropriately or not for each button being tapped.

The code is available on GitHub.


 XCTest Alert XCTest Alert



XCTestCase and life cycle of a test suite

XCTestCase subclass objects has all the required methods to setup and run a test case. More precisely methods for test suite life cycle.

a) class method setUp -> use this to initialize the inputs required , before the first test case executes.

override class func setUp(){
}

b) method setUp  -> executed every time before a test case runs

override func setUp() {
}

c) method tearDown -> executed every time after a test case execution completes.

override func tearDown() {
}

d) class method tearDown() -> use this method to do a clean up after all test cases are executed.

override class func tearDown(){
}

e) tearDown blocks -> These blocks are executed after the method execution of a test case is completed and before a tearDown() method is called. It can be used to close alert which is shown during the test case execution . You will be able to find this in the test case code which is shared.
XCTestCaselifecycle


Making your code ready for UITestCases

Let's learn something about accessibility identifiers here and how they are use full for testing.

accessibilityIdentifier is a string used to identify an element for the scripts written for UI automation testing.

ex: app.buttons["button2ID"].tap()

Here we are trying to get the button which has accessibilityIdentifier as "button2ID". This can be set from Identity Inspector as shown below.

AccessibilityIdentifier




Adding a new UI Test Target

In case you have existing project for which you want to a UITestCases. Go to Test Navigator -> New UI .

NewUITestCaseTarget
Add new UI Test Target for your project from the Test Navigator.


New UI Test case target with selection of Target under Test

Target to be tested is your main target 



Write your first test case.

All test methods start with prefix "test". Purpose of the this test is to check if Alert message is shown correctly or not. Here the test class name is AlertbuttonUITests which is subclass of XCTestCase.

Preparing your Class for UITest Case


import XCTest
@testable import AlertUITestcase

class AlertbuttonUITests: XCTestCase {
...........
...........
...........
}

1) All test Case scripts are subclass of XCTestCase class , which helps to get all the life cycle methods.
i.e setup and tearMethods

2) @testable attribute to the import statement, elevates the access of the module AlertUITestcase  as if they were public. 

- Classes and class members marked as internal or public behave as if they were marked open. 

- Entities marked as internal act as if they were declared public. 

- However it is limited to file-private and private declaration are not visible outside  of their usual scope of it's target.

This itself is not sufficient, there is one more setting in build which compiler needs to know that complied module is eligible for higher level access.



Enable Testability For Debug




Writing the test Case to Validate alert message being shown is correct or not.


  func testAlert1TapMessage(){
        
        let app = XCUIApplication()
    
        //Find the button with accessibilityIdentifier="button1ID" and tap on it
        app.buttons["button1ID"].tap()

        //Expect a Alert to be shown, get it as per the Title
        let alert = app.alerts["Alert 1"]
        
        //Alert Message should match the static Message Being set.
        XCTAssertTrue(alert.staticTexts[AlertUIMessageConstants.alert1Message].exists, "Alert 1 Message mismtach - wrong message is shown")
        
        //After the test execution is completed, close the alert.
        self.addTeardownBlock {
            alert.buttons["OK"].tap()
        }
        
    }

1) Get the UIApplication Proxy object using XCUIApplication(). This is required to query elements.

2) Now we want to tap the button with accessibility identifier "button1ID". Once we have the UIButton we wan a tap even so the code written in the main target shows the alert using UIAlertController.

3) Now as the XCUIApplication object "app" variable,  is subclass of XCUIElement which in turn implements protocol XCUIElementTypeQueryProvider we can query for button or alerts and the static texts in the interface using a string identifier. 

In the current scenario we are looking to Assert the alert has message "Alert 1 Tap", referenced by AlertUIMessageConstants.alert1Message.
If the message displayed matches the existence of the text then the test case is success or else it will be false.

4) addTeardownBlock , this is the place where we want to clean up what is being tested, For us it's as simple as dismissing alert by tapping ok.

Validating the test cases with code coverage (Enable Code Coverage)

Once we run all the test cases in the code finally, we can check the how much code is covered under our test case.

To enable Code Coverage we will have to enable it from Schema.

Enable Code Coverage Xcode


If we just have func testAlert1TapMessage(){  it will cover around 86.4 % of the code of ViewController.swift. In the below example we can simple disabling the test case for "Alert 2" button , reduces the code coverage. Which means some part of our code is not yet tested with automation script.

Check Code Coverage Xcode

"Alert 2" button test case is disabled , which checks message being displayed for other button is correct or not



As this was just for testing, let's re-enable and check the test case coverage report again.

Validate final Code Coverage




























Comments

Popular posts from this blog

hitTest on iOS to identify the view being hit

CMTimeMakeWithSeconds explained

Custom Editing Control for UITableViewCell , like iPhone Mail Appliation