Xcode 7 brings automated UI testing on board. It doesn’t seem perfectly stable yet, nor does it support all of the UI elements (as of beta 4), but it makes adding UI tests to the app fairly easy. Instead of setting up the environment for Appium, Calabash, or other frameworks, we only have to tap a checkbox to have a project with UI tests target set up.
To make UI tests self contained we can use HTTP mocking library (OHHTTPStub for a good example) and stub all the requests. This is pretty good solution already, but what always bothered me is that the app needs to modified for that, and the more we modify the app the farther away it goes from the binary we will are going to release.
The other solution is to use mock server outside of the app. This lets our binary send HTTP requests like it would in production environment and all the magic happens outside of our binary. I set this up using apimocker together with Charles HTTP Proxy. Apimocker is simple to set up API mocking tool (it also sports many useful features). Charles Proxy is actually the only tool I found so far that is capable of mapping requests.
For simplicity I will only write one test that will check for the number of forecast days. In Rain Shield app each day is represented by table cell, so to test if correct days number is displayed I only need to count table cells.
To quickly test for above condition, following line will suffice
At the start Rain Shield makes asynchronous request and only updates it’s views after receiving response. If the line above will execute immediately the test will fail. Here is where expectations come in handy. I expect for at least one cell to be present in order to execute the rest of the test.
1 2 3 4 5
The complete test class looks like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Hands on request-response manipulation
Rain Shield app executes one request to Open Weather Map API that gets the weather for following days and this is the request we want mapped and the response mocked.
apimocker_config.json to my project to tell apimocker what to do
1 2 3 4 5 6 7 8 9 10 11 12
This tells it to return content of daily_forecast_london.json file for every GET request to
We need to tell Charles to map requests going to
api.openweathermap.org onto address configured in apimocker -
localhost:1337/openweathermap. We do that in
Tools -> Map Remote tool.
In ‘Map From’ section we say that host is
api.openweathermap.org and we use wildcard
* as path (which will map everything).
In ‘Map To’ host is
1337 and path is
For this to work in Simulator we also need to enable Mac Proxying in Charles. Just make sure that
Proxy -> Mac OS X Proxy is checked.
Test Driving our setup
We only need to run apimocker now. After typing
we should see some feedback about our setup. After running Rain Shield app, Charles should show us request to localhost instead of openweather API.
apimocker should also print out that it mocked forecast response with
Yay! One advantage we get already is that the request is fast and is available offline, so it might be useful for developing as well.
Automating it for CI testing
Preparing Charles config
Charles has a nice config file that steers everything. We get the path to default config when we run Charles from command line
When we change configuration of Charles via UI the changes we make are reflected in this file. I reccomend first setting up our Remote Mapping and copy the file to our project once we have it.
To run Mac OS X Proxy at startup we need to set
1 2 3 4 5
I also don’t want Charles to check for updates during testing, so we can turn it off.
We can also enable web access, so that we can configure some things via browser under
1 2 3 4 5
And last but not least we can also see our remote mapping configuration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Once we have our config file prepared we can use it to run Charles without UI
One thing here is that it did not work for me with relative path to config file. It has to be absolute.
Starting our environment from script
To start Chalres and apimocker from cli we can use following script
1 2 3
open -ga opens app in background mode, passing everything after
--args as standard arguments to the app itself
If you don’t intend to have our environment running all the time, it is also easy to quit our programs within script
1 2 3