title: XCUITest: How to jump into app code? How to modify the state of the app under test?
body: <p>Coming from an Android/Espresso background, I am still struggling with XCUITest and UI testing for iOS.
  My question is about two related but distinct issues:</p>
  
  <ol>
  <li>How to compile and link against sources of the app under test?</li>
  <li>How to jump into methods of the app under test and modify its state at runtime?</li>
  </ol>
  
  <p>To tackle these questions, we should first understand the differences between XCode's "unit test targets" and "UI test targets".</p>
  
  <ul>
  <li><p>XCUITests run inside a completely separate process and cannot jump into methods of the app under test. Moreover, by default, XCUITests are not linked against any sources of the app under test.</p></li>
  <li><p>In contrast, XCode's unit tests are linked against the app sources. There is also the option to do "@testable imports". In theory, this means that unit tests can jump into arbitrary app code. However, unit tests do not run against the actual app. Instead, unit tests run against a stripped-down version of the iOS SDK without any UI. </p></li>
  </ul>
  
  <p>Now there are different workarounds for these constraints:</p>
  
  <ul>
  <li><p>Add some selected source files to a UI test target. This does not enable to call into the app, but at least it enables to share selected code between app and UI tests.</p></li>
  <li><p>Pass launch arguments via <code>CommandLine.arguments</code> from the UI tests to the app under test. This enables to apply test-specific configurations to the app under test. However, those launch arguments need to be parsed and interpreted by the app, which leads to a pollution of the app with testing code. Moreover, launch arguments are only a non-interactive way to change the behavior of the app under test.</p></li>
  <li><p>Implement a "debug UI" that is only accessible for XCUITest. Again, this has the drawback of polluting app code.</p></li>
  </ul>
  
  <p>This leads to my concluding questions:</p>
  
  <ul>
  <li><p>Which alternative methods exist to make XCUI tests more powerful/dynamic/flexible?</p></li>
  <li><p>Can I compile and link UI tests against the entire app source and all pod dependencies, instead of only a few selected files?</p></li>
  <li><p>Is it possible to gain the power of Android's instrumented tests + Espresso, where we can perform arbitrary state modifications on the app under test?</p></li>
  </ul>
  
  <h1>Why We Need This</h1>
  
  <p>In response to @theMikeSwan, I would like to clarify my stance on UI test architecture.</p>
  
  <blockquote>
    <p>UI Tests should not need to link to app code, they are designed to
    simulate a user tapping away inside your app. If you were to jump into
    the app code during these tests you would no longer be testing what
    your app does in the the real world you would be testing what it does
    when manipulated in a way no user ever could. UI tests should not have
    any need of any app code any more than a user does.</p>
  </blockquote>
  
  <p>I agree that manipulating the app in such a way is an anti-pattern that should be only used in rare situations.
  However, I have a very different stance on what should be possible.
  In my view, the right approach for UI tests is not black-box testing but gray-box testing. Although we want UI tests to be as black-boxy as possible, there are situations where we want to dig deep into implementation details of the app under test.
  Just to give you a few examples:</p>
  
  <ul>
  <li><p><strong>Extensibility:</strong> No UI testing framework can provide an API for each and every use case. Project requirements are different and there are times where we want to write our own function to modify the app state.</p></li>
  <li><p><strong>Internal state assertions:</strong> I want to be able to write custom assertions for the state of the app (assertions that do not only rely on the UI). In my current Android project, we had a notoriously broken subsystem. I asserted this subsystem with custom methods to guard against regression bugs.</p></li>
  <li><p><strong>Shared mock objects:</strong> In my current Android project, we have custom hardware that is not available for UI tests. We replaced this hardware with mock objects. We run assertions on those mock objects right from the UI tests. These assertions work seamlessly via shared memory. Moreover, I do not want to pollute the app code with all the mock implementations.</p></li>
  <li><p><strong>Keep test data outside:</strong> In my current Android project, we load test data from JUnit right into the app. With XCUITest's command line arguments, this would be way more limited.</p></li>
  <li><p><strong>Custom synchronization mechanisms:</strong> In my current Android project, we have wrapper classes around multithreading infrastructure to synchronize our UI tests with background tasks. This synchronization is hard to achieve without shared memory (e.g. Espresso IdlingResources).</p></li>
  <li><p><strong>Trivial code sharing:</strong> In my current iOS project, I share a simple definition file for the aforementioned launch arguments. This enables to pass launch arguments in a typesafe way without duplicating string literals. Although this is a minor use case, it still shows that selected code sharing can be valuable.</p></li>
  </ul>
  
  <blockquote>
    <p>For UI tests you shouldn't have to pollute your app code too much. You
    could use a single command line argument to indicate UI tests are
    running and use that to load up some test data, login a test user, or
    pick a testing endpoint for network calls. With good architecture you
    will only need to make the adjustment once when the app first launches
    with the rest of your code oblivious that it is using test data (much
    like if you have a development environment and a production
    environment that you switch between for network calls).</p>
  </blockquote>
  
  <p>This is exactly the thing that I am doing in my current iOS project, and this is exactly the thing that I want to avoid.
  Although a good architecture can avoid too much havoc, it is still a pollution of the app code. Moreover, this does not solve any of the use cases that I highlighted above.
  By proposing such a solution, you essentially admit that radical black-box testing is inferior to gray-box testing.
  As in many parts of life, a differentiated view is better than a radical "<em>use only the tools that we give you, you should not need to do this</em>".</p>