With the proliferation of iOS devices year over year, the threshold of iOS success is higher than ever before. More companies like startups and SMEs find it not financially sustainable to acquire every piece of iOS devices with different OS versions and HW specs. On the other way, testing apps or games manually is not anymore an ideal option for the QA process due to low efficiency and scalability issue.

Though iOS is still a more closed operating system compared to Android, many open-source test automation frameworks and tools can be utilized to create robust automated tests. Along with the help of a cloud-based testing solution, it enables developers/testers to verify app quality more efficient in a scalable way and makes iOS testing tasks easier.

Today we’d like to go through 5 widely used iOS testing frameworks nowadays with simple code samples to give you a basic understanding of getting started with your iOS testing. If you are also interested in Android test automation frameworks, do not forget to check out the top 5 Android automated testing frameworks with code examples, where code samples are provided as well.

1. Appium

Appium is popular due to its flexibility and usability on both Android and iOS, and it works on native, hybrid and web applications. For iOS testing, it uses JSONWireProtocol to engage with iOS applications using Selenium WebDriver. Thanks for that, Appium does support mobile web testing very well and its use cases are very similar as if Selenium would be used for web testing. Download our Appium beginner’s guide to learn how to set up Appium for mobile app testing.

Appium code sample:

driver.findElement(By.id("com.example.app:id/radio0")).click(); driver.findElement(By.id("com.example.app:id/radio1")).click(); driver.findElement(By.id("com.example.app:id/radio2")).click(); driver.findElement(By.id("com.example.app:id/editText1")).click(); driver.findElement(By.id("com.example.app:id/editText1")).sendKeys("Simple Test"); driver.findElement(By.name("Answer")).click(); // or alternatively with driver.findElement(By.id("com.example.app:id/button1")).click();

2. XCTest / XCUITest

XCTest and XCUITest are two integral test automation frameworks for iOS app testing. XCTest allows developers to write tests for components at any level and also provides the framework for UI testing capabilities. XCTest tests are grouped into subclasses of XCTestCase.

Typically XCUITest is used for functional testing, automating tests of common workflows, demo sequences or behavior of customer views.

The framework comes with XCUITest Recorder, a tool for recording the first steps of the automated test. To find elements, their properties and navigating through the element tree of the application, one can also make use of the interface builder. Looking at XCTest/XCUITest for iOS app testing? Download our free guide to leverage the framework in your daily iOS testing job.

As for programming languages, XCTest/XCUITest is fully compatible with both Objective-C and Swift.

Code sample with Objective-C:

- (void)testClicksOnRadioButtons { [tester tapViewWithAccessibilityLabel:@”Radio1”]; [tester tapViewWithAccessibilityLabel:@”Radio2”]; [tester tapViewWithAccessibilityLabel:@”Radio3”]; [tester enterText:@”Simple Test” intoViewWithAccessibilityLabel:@”editText1”]; [tester tapViewWithAccessibilityLabel:@”Answer”]; }

Code sample with Swift

testClicksOnRadioButtons() { let app = XCUIApplication() app.radiobutton[0].tap() app.radiobutton[1].tap() app.radiobutton[2].tap() app.staticTexts[“Simple Test”] app.button[0].tap() }

Learn and get started with KIF by reading our blog about this: How to get started with KIF?

3. Detox

Detox is a gray box end-to-end testing and automation framework for mobile apps. Like Appium and Calabash, one of the biggest advantages is that it supports cross-platform on both Android and iOS. The only issue is that Detox is not supported to run on real iOS devices yet. Bitbar supports Detox tests on Android devices, though.

Detox code sample:

it('should have bitbar question element visible', async () => { await waitFor(element(by.id('question_screen'))).toBeVisible().withTimeout(6000); await device.takeScreenshot('app-open'); await expect(element(by.id('question_screen'))).toBeVisible(); await expect(element(by.id('question_screen').withAncestor(by.id('question_text')))); }); it('should have text input field visible', async () => { await waitFor(element(by.id('text_input_field'))).toBeVisible().withTimeout(6000); await expect(element(by.id('text_input_field'))).toBeVisible(); });

4. Calabash

Calabash is another great cross-platform framework that works perfectly with Android and iOS apps. One of the major differences to other frameworks is that Calabash tests are written in Cucumber. That means the test is written like a specification and is simple and easy to read even for non-tech people, but still executable by the automation system. Download this Calabash 101 to sharpen your Calabash skills and master this framework.

Calabash code sample:

Feature: Answer the Question feature Scenario: As a valid user I want to answer app question I wait for text "What is the best way to test application on hundred devices?" Then I press Radio button 0 Then I press Radio button 1 Then I press Radio button 2 Then I enter text "Simple Test" into field with id "editText1" Then I press view with id "Button1"

5. EarlGrey

To some degree, EarlGrey is the ‘Espresso for iOS’. It’s also developed and open-sourced by Google. Google uses this test framework to test many iOS native apps including Google Calendar, YouTube, etc. As the codename goes, lots of similarities can be found between Espresso and EarlGrey. For example, EarlGrey tests will automatically wait for events (animations, network requests etc.) before trying to interact with the UI.

EarlGrey code sample:

- (void)testBasicSelectionAndAction { [[EarlGrey selectElementWithMatcher::grey_accessibilityID(@"ClickHere")] performAction:grey_tap()]; // Example of long press with EarlGrey matchers - (void)testLongPress { [[EarlGrey selectElementWithMatcher::grey_accessibilityLabel(@"Box")] performAction:grey_longPressWithDuration(0.5f)]; [[EarlGrey selectElementWithMatcher::grey_accessibilityLabel(@"One Long Press")] assertWithMatcher:grey_sufficientlyVisible()];// Example of multi-select, visible click on items - (void)testCollectionMatchers { id visibleSendButtonMatcher = grey_allOf(grey_accessibilityID(@"Box"), grey_sufficientlyVisible(), nil); [[EarlGrey selectElementWithMatcher:visibleSendButtonMatcher] performAction:grey_tap()]; }

Bonus: Jest / Jasmine

Jest uses Jasmine behavior-driven framework as the basis for testing JavaScript code. Every test case starts from the describe() function call, similar to how JUnit uses TestCase class. The describe() function takes 2 parameters – the description/title of the test case and the function to be executed. The it() function includes all the test steps and provides (similar to JUnit) series of expect() functions.

Jasmine code sample:

describe("Player", function() { var player; var song; beforeEach(function() { player = new Player(); song = new Song(); }); it("should be able to play a Song", function() { player.play(song); expect(player.currentlyPlayingSong).toEqual(song); //demonstrates use of custom matcher expect(player).toBePlaying(song); }); describe("when song has been paused", function() { beforeEach(function() { player.play(song); player.pause(); });it("should indicate the song is paused", function() { expect(player.isPlaying).toBeFalsy(); // demonstrates use of 'not' with a custom matcher expect(player).not.toBePlaying(song); }); it("should be possible to resume", function() { player.resume(); expect(player.isPlaying).toBeTruthy(); expect(player.currentlyPlayingSong).toEqual(song); }); }); // demonstrates use of spies to intercept and test method calls it("tells the current song if the user has made it a favorite", function() { spyOn(song, 'persistFavoriteStatus'); player.play(song); player.makeFavorite(); expect(song.persistFavoriteStatus).toHaveBeenCalledWith(true); }); //demonstrates use of expected exceptions describe("#resume", function() { it("should throw an exception if song is already playing", function() { player.play(song); expect(function() { player.resume(); }).toThrow("song is already playing"); }); }); });

Conclusion

Though iOS app testing is totally different than Android app testing, you can use either Appium or Calabash to create test scripts that can be used to do cross-platform testing. That being said, every framework has its advantages and every one of you has different needs for the projects you are working on. It’s recommended to do some further research, learn more about each framework and choose the one you are comfortable with. Happy iOS testing.