Search code examples
fixturesxcode-ui-testingui-testing

Application State / Test Fixtures with Xcode UI Tests


A pretty common problem with any kind of integration test is getting the unit under test into a known state -- the state that sets up well for the test you want to perform. With a unit test, there's usually not much state, and the only issue is in potentially mocking out interactions with other classes.

On the other hand, when testing a whole app there's all sorts of potentially persistent state, and getting the app into a clean state, or trickier still, into a known state that isn't "clean" without any access to the app itself is a little tricky.

The only suggestion I've found is to embed any necessary setup in the app, and use something like an environment variable to trigger setup. That is, of course, viable, but it's not ideal. I don't really want to embed test code and test data in my final application if I can avoid it.

And then there's mocking out interactions with remote services. Again you can embed code (or even a framework) to do that, and trigger it with an environment variable, but again I don't love the idea of embedding stubbing code into the final app.

Suggestions? I haven't been able to find much, which makes me wonder if no-one is using Xcode UI testing, or is only using it for incredibly simple apps that don't have these kinds of issues.


Solution

  • Unfortunately, the two suggestions you mentioned are the only ones that are possible with Xcode UI Testing in its current state.

    There is, however, one thing you can do to mitigate the risk of embedding test code in your production app. With the help of a few compiler flags you can ensure the specific code is only built when running on the simulator.

    #if (arch(i386) || arch(x86_64)) && os(iOS)
        class SeededHTTPClient: HTTPClientProtocol {
            /// ... //
        }
    #endif
    

    I'm in the middle of building something to make this a little easier. I'll report back when its ready for use.