Supercharging Continuous Delivery with KiF iOS UI Automation

kif_continuous_integration

From car manufacturing to software engineering, there has always been an ongoing pursuit for teams to leverage their process of delivering value as a competitive advantage. In the quest for a more-perfect process, Continuous Delivery stands as the tantamount answer to the burning questions of how teams can be more agile, innovative, and adaptive to market feedback.

The process of developing quality iOS applications is no different. Our iOS apps not only need to be developed with clean code and architecture, but they also need to be vetted through a pipeline of rigorous tests: unit, integration, automation, etc… Having this automated pipeline that developers can leverage ensures that new features do not introduce regressions, for example, and that what is actually built matches the vision of how our apps are expected to work.

Lately, I have been fascinated with the idea of building this pipeline in mind, and have been exploring options for automation in iOS applications. I have played with everything from UI Automation, Appium, Frank, and KiF. I have had some fun working with all of them and learning how they work, and though I do believe that every framework has its advantages and quirks, I fell especially in love with KiF. 

The following post outlines the things I found out about KiF that are not so obvious when I was first getting started. I will be going over the accessibility inspector, using KiF with UIWebViews, using the page object pattern, and using all this with preprocessor macros. I will be assuming that you already have your project set up with KiF. If not, I highly recommend using KiF with CocoaPods, or just head over to the getting started guide here: https://github.com/kif-framework/KIF.

Take Advantage of the Accessibility Inspector

The first step to starting out with KiF is to understand how it works by turning on iOS Simulator’s “accessibility inspector”. The underlying layer that KiF leverages to tap on elements of the view hierarchy is the built-in accessibility features of iOS. By turning on the accessibility inspector in the simulator, we can inspect our elements on screen, see what the labels of our elements are (if we have not assigned them in code), and view what kind of traits the UI element has. 

To turn on the accessibility inspector, go to Settings > Accessibility > and toggle the “Accessibility Inspector” to the on position. Doing so will pop up a window that will inform you about elements you click with your mouse on the screen. To continue simulating tap gestures with this inspector on, just double tap on the same element. To quickly disable or enable the inspector, just click on the close button found on its pop-up window.

With KiF integrated and the accessibility inspector enabled, you will never have to guess what the name of the element you want your automation test to tap on is called. This tool will prove immensely useful in allowing you to write and debug your KiF tests much more efficiently because you essentially seeing what KiF “sees”. 

Inject Javascript Into UIWebViews to Interact with DOM Elements

KiF can also be extended to interact with elements in a web view, allowing you to test parts of your app that might rely on the user navigating some sort of web resource, like an OAuth flow for example. All KiF needs are some accessibility elements that are written in the DOM, which can be implemented as “title=“ attributes on your DOM elements that the Accessibility feature in iOS will automatically use as those elements’ labels in the accessibility inspector. 

In cases where I have not had access to write privileges for that web resource I need to test, I have utilized injecting javascript into the UIWebView to programmatically label elements on the screen for me. For example, in the delegate method:

- (void)webViewDidFinishLoad:(UIWebView *)webView

I have written conditions to figure out what webpage I am currently on, use Chrome’s inspector and interactive javascript console to write a quick loop to label the elements I want to interact with, and inject the labels using UIWebView’s stringByEvaluatingJavaScriptFromString method. Finally, I use preprocessor macros to ensure that these injections do not appear in production and only appear when we are running tests.

Now you have a really great way to extend KiF’s ability to work with DOM elements, which could definitely come in handy if you ever have to test web apps wrapped in frameworks like PhoneGap.

Extend KiF’s Test Actor to Work With UIWebView Forms

One problem I have run into is KiF’s inability to interact with UIWebView form elements. Having a test that had KiF type values into an HTML input field would always result in a test failure. A call to the following method in the KiFUITestActor class

 

- (void)enterText:(NSString *)text intoViewWithAccessibilityLabel:(NSString *)label

resulted in a failure despite the fact that KiF was typing the correct values. Upon further inspection, it seems as though the above method relied on an internal method that does a validation check to see if the accessibility element has the expected text, but for whatever reason that always failed. To get around this validation, just copy the entire definition of the following method and create your own category that your UI tests will instead rely on for web view form elements:

- (void)enterText:(NSString *)text intoViewWithAccessibilityLabel:(NSString *)label traits:(UIAccessibilityTraits)traits expectedResult:(NSString *)expectedResult
{
    UIView *view = nil;
    UIAccessibilityElement *element = nil;
    
    [self waitForAccessibilityElement:&element view:&view withLabel:label value:nil traits:traits tappable:YES];
    [self tapAccessibilityElement:element inView:view];
    [self waitForKeyboard];
    [self enterTextIntoCurrentFirstResponder:text fallbackView:view];
}

With this implemented, you have extended the KiFUITestActor class to interact with UIWebView forms! (Note: I got inspiration from this gist here. Gotta give credit where credit is due: https://gist.github.com/seansu4you87/1904424)

Leverage The Page Object Pattern

Similar to how we would organize our Selenium tests, we can also organize our KiF UI tests by using the Page Object pattern. For every test, import all of your page object classes, which will tell your actor how to interact with elements in your views. 

For example, say we have a table view of tweet IDs that can be drilled down to another view to see the author and the tweet contents. If I were to write a UI test for this, I would first create two page object classes: one for my table view, and one for my detail view. The table view page object class would know how guide my test actor to find and tap on a row in the table, and perhaps how to tap the refresh button on the table view. My detail view page object might have a method that knows how to return to the last screen, for example. 

The test class I would write would import both of these page objects, and in my test method I would instantiate a test actor object that would be passed to the page object methods. This way,t he page object classes guide the actor through the interaction of the app without the actor having to know how to inherently interact with all the views itself. As illustrated above, this can be a very powerful pattern that allows us to compartmentalize our tests away from the frameworks we are using as much as possible. 

Use UI Test Preprocessor Macros

Sometimes I have had to run special code blocks in my view and view controller classes to properly get my KiF tests running. For example, I have written code blocks that clear all user data before any UI tests run so I can simulate a fresh build every single time. Obviously, we would never want this to run in our apps outside of our UI test target. The way that I have ensured that those code blocks only run in cases where I am running my UI test targets is by relying on preprocessor macros that I can switch on or off. I can then write conditions that test for if those macros are defined, thus ensuring that my UI test code never gets executed in a production environment. This ends up being a really clean way of integrating UI tests into my app without sacrificing readability of my code base. 

Conclusion

While there is so much more to cover about KiF, I believe these tips will be ample to start iOS developers off who are looking for more than just a “getting started” guide. My hope is that through this article, an iOS developer out there would find value in building a test automation step into their pipeline.

Also on a higher intellectual level, It is intellectually stimulating to wrap my head around the idea that it is less about what you build and go to market with, and more with how you go about building your vision, how you work together in an organization, and how you adapt to market changes and trends that really determines success for your app. For iOS developers, leveraging an automation framework will prove invaluable to our ability to deliver features quickly while assuring quality. Hopefully this article gets more of us iOS developers out there a nice starting point to build that vision.