Andreas Böhrnsen

Consulting and Development

Don't be blind when KIF fails on Travis

Do you test your iOS app? You should! The best way to test is to simulate and automate user interaction - like a real human would use the app. You can test real use cases and your full stack. KIF is great for that on iOS. It integrates nicely into XCode and it can even take screenshots when it fails. But how to get the screenshots out when we use Travis? Here is how.


This article focuses on using KIF for iOS Acceptance Testing. However the way how to get the screenshots out can also be applied to other frameworks like Selenium web testing.

Let me assume that you have a basic understanding of

There are a lot of wonderful resources on the net if you need to get a quickstart.

Using KIF

Setting up KIF is nicely described in the docs on the KIF website. To keep things organized let’s use CocoPods for dependency management.

Initial Setup

The most important thing to mention is that we have to use the :head version. The current version 2.0.0 is about 6 months old and does not support taking screenshots yet.

We change the version in the Podfile as follows:

# Testing
target 'Acceptance Tests', :exclusive => true do
  pod 'KIF', :head # <- change version

To set up automated testing in Travis we have to initialize a .travis.yml file with the following contents:

language: objective-c
  - 1.9.3

Note that I use Ruby 1.9.3. During my tests CocoaPods was always segfaulting on Ruby 2.0. This may be fixed now and not necessary anymore.

Having this in place would already install your Cocoapods dependencies and run all tests.

Taking Screenshots

As mentioned before KIF only supports taking screenshots in :head or version greater than 2.0.0 (not released yet).

To enable taking screenshots we need to set the environment variable KIF_SCREENSHOTS that tells KIF where to output the images. We just use a directory called “Screenshots” and create it before running the test scripts.

Let’s test this locally before adding it to the Travis config.

Testing locally

$ mkdir Screenshots
$ export KIF_SCREENSHOTS="`pwd`/Screenshots"

Then create a sample test class like this


#import <KIF/KIF.h>

@interface SampleTests : KIFTestCase


#import "SampleTests.h"

@implementation SampleTests

- (void)testTakingScreenshotsOnFailure
    [tester tapViewWithAccessibilityLabel:@"this cannot be found"];


and run the tests from the command line. Travis uses xctool. So it would be best to use this as well. It can be installed with Homebrew on the Mac.

$ brew install xctool

You may also want to read the previous blog post as it gives a short intro to xctool as well.
In my case the test command looked like this:

$ xctool -workspace iOpenSongs.xcworkspace -scheme Beta -sdk iphonesimulator test

If you get a screenshot of the start screen it worked!

Configuring Travis

In the .travis.yml file it looks like this:

language: objective-c
  - 1.9.3
  - mkdir -p $KIF_SCREENSHOTS
  - xctool -workspace iOpenSongs.xcworkspace -scheme Beta -sdk iphonesimulator test

Extracting the Screenshots from Travis

On Travis it would now take screenshots whenever a test fails. This is great! But how do we access the screenshots that have been taken?

We could

For me the easiest seemed to “upload them to S3”.

Uploading the screenshots to S3

For uploading to S3 from the command line we can use s3cmd. Again, let’s test it before adding it to the Travis config.

Testing locally

s3cmd can be found and installed with Homebrew on a Mac

$ brew update
$ brew install s3cmd

To configure it simply run

$ s3cmd --configure

This will ask you for your S3 credentials and store them in ~/.s3cfg.

Now we can list all our buckets to test the credentials.

$ s3cmd ls
2013-11-06 02:37  s3://my-full-bucket

Seems to work. So we can create a new bucket for the screenshots.
Be aware that bucket names are unique across all users. Let’s use a FQDN-named bucket to work around this.

$ s3cmd mb s3://

Now we can try to upload a file

$ s3cmd put testfile s3://

If that works we are ready to put it into our Travis config.

Configuring Travis

Create a new s3cmd config file .s3cfg in your project folder and add the minimal config


Just add your own access_key for now. We will encrypt the secret_key for security reasons.
You may also study the other options and add them as needed. For that check your ~/.s3cmd file or execute s3cmd --dump-config.

To encrypt your secret_key we can use Travis’ “encrypted environment variables” feature. The variables are encrypted/decrypted with public and private RSA keys that Travis generates on a user basis.

For this we need the Travis CLI tool that can be installed with Ruby Gems. Afterwards we need to authenticate to the Travis API.

$ gem install travis
$ travis login

Now we can encrypt the secret_key as an AWS_SECRET environment variable.

$ travis encrypt AWS_SECRET=fKJF1yXHjLwQ/9r77Sm9Z3k62oBiEmKc3HrMsVwf --add

The --add parameter adds the encrypted variable to the .travis.yml file automatically.

Travis has an after_failure hook that we can use to install s3cmd and to upload the screenshots whenever the tests fail. So we add the following to the Travis config

  - brew update
  - brew install s3cmd
  - echo "secret_key = $AWS_SECRET" >> .s3cfg
  - s3cmd put --guess-mime-type --config=.s3cfg $KIF_SCREENSHOTS/* s3://$TRAVIS_JOB_NUMBER/

Remember to modify the s3 bucket accordingly :)

Here we go. That’s it. This will

when Travis fails.

To access the screenshots you could use a GUI tool like Cyberduck or s3cmd if you prefer the command line.


Here is a screenshot using Cyberduck. You can see that the filename reflects in which file and line the test failed.


For your reference here is the full .travis.yml

language: objective-c
  - 1.9.3
    - secure: N0tEZ7I8F...
  - mkdir -p $KIF_SCREENSHOTS
  - xctool -workspace iOpenSongs.xcworkspace -scheme Beta -sdk iphonesimulator test
  - brew update
  - brew install s3cmd
  - echo "secret_key = $AWS_SECRET" >> .s3cfg
  - s3cmd put --guess-mime-type --config=.s3cfg $KIF_SCREENSHOTS/* s3://$TRAVIS_JOB_NUMBER/

You can take the whole procedure even one step further and test across multiple iOS versions. This is described in my previous blogpost.


Share this post on:
comments powered by Disqus