I have now been testing mobile devices (both iOS and Android) for roughly 9 months now, and boy has it been an experience. Very steep learning curve for me. One of the most useful techniques I have found in testing and debugging is the ability to monitor the traffic going through the network, not just to verify what is being sent but also monitor things like request and response headers and contents, http response codes and the likes.
In web development (or using mobile simulators or emulators) you would use an http proxy program, something like Fiddler, Firebug (for FIrefox), Google Dev tools, Charles, or some other tool, but how do you do this from a mobile device? The short answer is exactly the same way, you just need to make sure all traffic from the mobile device is going through your choice of http proxy tool.
This post will explain how to set this process up using Charles in OSX on a MacBook Pro, but technically the same should work regardless of your toolset (not sure how different tools would handle SSL traffic).
Note: This is not intended to be a “How to use Charles” guide (there is a lot more to Charles than what I will be covering here!)
Install and Set-up Charles
Charles can be installed from http://www.charlesproxy.com
As tools go, it’s pretty simple to set-up and install. The only things really worth mentioning are:
- Make sure you switch on Enable transparent HTTP proxying under Proxy -> Proxy Settings.
- Take note of the Port Number Charles is using on the above Proxy Settings screen. You’ll be using it soon.
- Under Proxy -> Recording Settings you may want to define a list of traffic to either Include or Exclude. This will help reduce the amount of noise you have to wade through to see the traffic you really want (particularly if you are on a corporate network).
Apart from that, everything else falls under the umbrella of ‘standard Charles functionality’.
Configure Mobile device
Now we need to get the traffic going from the mobile device through Charles. This is simple if your mobile device is connected to the same wifi network as the computer running Charles. If it is not you will need to find a way for the computer in question to become visible to the mobile device, for example sharing your Mac’s internet via wifi and connecting the phone directly to it.
Disclaimer: By sharing your computer’s wifi you are essentially allowing another connection to your internal network. Make sure you set it up with security and definitely get permission from your network administrator, particularly if on a corporate network, before attempting this. They may be able to provide another solution.
Directing traffic through Charles is as simple as setting up the proxy on your mobiles wifi connection.
- Get the local IP Address of the computer running Charles
- You can use either the IP address under System Preferences -> Network or the local IP address returned by the option under Charles’ Help menu. Both seem to work.
- Configure your iPhone to use the wi-fi network that has access to the computer running Charles
- Set the proxy of the wi-fi network to Manual
- Enter the IP address of the local pc from the step above
- Enter the Port number the is set in Charles
All traffic should now be visible in Charles
Configure for SSL usage
So far all traffic should be visible, but the contents of any SSL traffic (and lets face it, that’s the stuff we want to be looking at) will still be hidden. Here’s how to get access to it:
- On the mobile device, open a web browser and navigate to http://charlesproxy.com/charles.crt and accept/install the certificate. This authorises traffic from the mobile to be viewable in Charles
- In Charles, navigate to Proxy -> Proxy Settings -> SSL Tab
- Enable SSL Proxying and add the Location(s) you want to monitor
Note: While this works for most SSL traffic, some server certificates are set-up in such a way to prevent man-in-the-middle attacks. Because of this they will fail an SSL handshake, and therefore fail the request. There is a way to code around this (documented here), but while you still get the data encryption features of SSL, you lose the host identify validation features.
And you’re done! You should now be able to use the power of Charles to monitor and control the traffic being sent to and from the mobile device.
“But why is this useful in testing?” I hear you ask. What does this give you that you can’t get from running a build in a local development environment using a simulator and monitoring the console? On top of running the build locally and monitoring consoles, etc, I use this for four main reasons or scenarios:
- Testing of logging functionality. When testing things like Google Analytics, New Relic, Splunk, Crashlytics or your favourite form of monitoring or logging, before entering a full end to end testing scenario monitoring the network traffic for these calls is useful for monitoring the content of each call, the response from the logging server as well as how many calls are being made. I’ve lost count of the number of times I’ve noticed a double hit on a specific page hit due to bugs in the app’s navigation stack.
- Testing of app ‘post’ build pipeline. Depending on your environment and deployment setup, or how many build targets you have, your build pipeline may enforce numerous configuration changes depending on what build you are testing. By testing using network traffic you have full visibility of how the app you are going to distribute (or even have already distributed) is operating.
- Testing of specific scenarios dependant on message content. In some scenarios I find it quicker to test specific scenarios by modifying a specific call to the server to force a specific response. An example of this I did recently is to test a feature where we want to force a user to upgrade depending on what version of the app they have. Ordinarily you would need to install a specific version in order to test this, however considering the fact that in this instance the version number is being sent through in the request header it is a lot quicker and easier to put a block on the request, modify the build version in the header, then execute it and verify the response. Doing it this way means not only can you test the specific scenario, but also execute some exploratory scenarios, e.g.: What happens if the version number is in a different format (eg: if you want to change it to cater for Beta/Pilot builds).
- Cross-device support. Particularly if you are testing multiple development platforms (eg: iOS, Android, Windows Phone) you may not have all development environments set-up locally. By using this network monitoring method of testing you are completely non-dependant on any local set-up. This has also come in extremely useful for me in scenarios where I get a “It doesn’t work on MY phone” complaint for a scenario that works everywhere else. I find it a lot quicker and easier to debug whether issues are phone related, data related, or app related.
I hope that helps others. It’s certainly been useful to me.