Mocking URL request with Xcode 7 UI Testing
Mocking URL request with Xcode 7 UI Testing
I started answering a question on Apple’s new dev forums and decided it would be better as a simple blog post.
(The question was “UI Testing Mocking Data Xcode 7â€, https://forums.developer.apple.com/message/25973 )
Super simple overview of problem I want to solve:
- New UI Tests run in separate process from app, so my old way of mocking URL responses would no longer work
- I did not want any dependencies on external servers or processes
- I wanted to have everything about my UI Test case embedded in the test case file itself
- It needs to run on a CI server like Jenkins
My solution (currently a work in progress)
My solution is a little more involved than I would like, but I think it will work pretty well for me.
To make this work, I need to do some minimal setup in the app itself to make it “test readyâ€. Since there are only two ways a UI Test case can cause changes of any kind in the app:
- The actual UI interaction (the main point of the test)
- The launch arguments for XCUIApplication
Summary of changes to the app itself
My goal was to make the minimum set of changes to the main app as I could:
- Added a class, TestingProxyClient, which uses NSURLProtocol to call a proxy for all network requests
- Added some helper functions in StartupControl.m to interpret the launch arguments passed from the test case (StartupControl also initializes the proxy client)
- Updated app’s main.m to call the setup function defined in StartupControl
Summary of changes to the test cases
- Start a embedded webserver to act as a network proxy (using BCDWebServer, available on github)
- Use launch arguments of XCUIApplication instance to pass values to the app (including the proxy address & port)
Still to do:
- Port my existing mock data supplier to this new structure
Other changes
Update #3 (01-Aug-2015): Back to red: The dialog started appearing again for reasons I cannot discern…bummer.  (I made no changes to version of Xcode, beta or production, so I’m confused)
Update #2: Apparently the answer is much simpler and I was over thinking it. I’ll hold off final judgment for a day or two though.  I added ‘Xcode-beta.app’ to the exception list in the firewall options panel and it seems happy again.
Update: This apparently does not fix the issue — the dialog started appearing again today and what I thought fixed it yesterday does not work today…hmm, back to the drawing board.
One other change was necessary to ensure I could run this on a CI server without any user intervention. When you start up a web server in the simulator, I was getting the application firewall permissions prompt every time. Â Obviously, turning off the firewall completely would remove the prompt, but seems like a bad idea.
It probably took me longer than it should have to figure out the answer, but it is reasonably straight forward. There are two steps:
- ensure the application firewall’s automatically allow signed apps permission is checked
- ensure the XCTRunner binary is signed (this is the actual OS X app that runs the UI tests, not sure why it wasn’t signed by default on my machine)
- select Security & Privacy from settings
- click the Lock icon to make changes
- click the Firewall options button
- ensure the “Automatically Allow Signed Apps…†checkbox is checked
- /usr/libexec/ApplicationFirewall/socketfilterfw –setglobalstate on
- /usr/libexec/ApplicationFirewall/socketfilterfw -s “/Applications/Xcode-beta.app//Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Agents/XCTRunner.app/XCTRunner”
Tentative conclusion
I think I have solved all the issues that would prevent this from working and am finishing up the implementation now
This approach lets me put almost everything in just the test case: UI steps, data to mock, etc. which should make it reasonably straightforward to run on our CI server (Jenkins). Â
This will also let individual test cases setup the mock data supplier with the URLs and responses to mock.
Hopefully this will help someone else out there
Â