Mocking objects with Xcode 7 UI Automation
Asked Answered
R

1

13

I was using KIF Framework until now for iOS UI Automation. KIF (also Unit Test) targets runs the Unit/UI testing code in the same process as your application is running and we can easily Mock different objects/classes used by the app to show mock data.

When switching to Xcode 7 based new UI Automation, I found that UI Unit Test target runs in separate process and it launches the application in separate process. And thus it's not possible to access App classes/objects through unit tests and mock them.

Did anyone faced the same issue, and know about any workaround?

Please let me know if any more details are needed.

Answer: Please see the detailed answer below. Also here is link to reply from Apple devs: https://forums.developer.apple.com/thread/23552

Redcoat answered 21/10, 2015 at 18:48 Comment(0)
E
13

Because you are running in a different process, there isn't really a way to inject mocks into your application via your tests. Having said that, you do get to control your App's process, and can thus have some effects on it.

I've gone back and forth on how I feel about this (I'm currently undecided), but you could add some code to your app that reads an environment variable (via NSProcessInfo) that makes the app behave differently (i.e., change out what your dependency injection is injecting into your class so it uses mocks).

The downside to this is the mock code isn't contained strictly in the test bundle, and you end up with that code in your app (unless you use #if statements to isolate it). Obviously it's also important to be prudent with your code branching, so you don't invalidate your testing.

You could setup an environmental variable prior to launching the app in your UI test:

let app = XCUIApplication()
app.launchEnvironment = ["UITestUseMocks" : "true"]
app.launch()

Then in your application you can check for that, possibly in a #if statement and alter your behavior:

#if TEST_TARGET
    if let useMocks = NSProcessInfo().environment["UITestUseMocks"] where useMocks == "true" {
        // Alter services used in dependency injection or some other testing behavior
    }
#endif

I've been considering this approach for implementing a mock service layer that just replays some canned server responses so I can make my UI tests not depend on server responses (other things test the server, after all).

Ethic answered 23/10, 2015 at 20:20 Comment(2)
Oh wow! This breaks the whole dependency injection idea. I definitely don't want to introduce testing code in my production code. This is REALLY a showstopper.Flatting
@Flatting I agree, although if you wrapped everything in the compiler directives I mention above you wouldn't technically be introducing such code into your production binary (assuming your compiler flags are setup correctly). Having said that, it's obviously not ideal and easy to get wrong.Ethic

© 2022 - 2024 — McMap. All rights reserved.