Reputation: 148
KIF works like magic, something puzzled me a lot recently. That is how exactly KIF and XCTest works.
It is said in WWDC 2014 & 2013: Test code is injected into the host application as kind of a plugin, so what information can be eavesdrop from main app as a plugin? What is the relationship between Host Application & Plugin??
Using KIF, we can sense the Notifications & URL request, but how that works? My first thought is all context in host application is shared with plugin But why in test, we cannot modify variables in the main app?
For example:
we have two targets:
Magic Project
-- MagicApp
-- MagicUITest <- KIFTest target
Suppose I have a file called MagicClass:
class MagicClass {
static var a = 1
}
Is that possible if I want to modify that variable in MagicUITest?
The problem I faced right now is how can I inject different UIViewController to RootViewController so that I can run KIF test from each individual ViewController and don't need bother going through the login process all the time .. my guess is something like:
in MagicApp:
class AppDelegate : .. , .. {
func application(application: UIApplication, willFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
if MagicClass.a == 1 {
window.rootViewController = AViewController()
} else {
window.rootViewController = BViewController()
}
}
}
in KIFTest's setUp() :
setUp() {
Magic.a = 2
}
But not work ..
One thing is Magic.a = 2 won't change the Magic.a in MagicApp, second is application(..,..,..) function will end before setUp() is called ..
Any idea ?
Upvotes: 2
Views: 1258
Reputation: 81132
While you're correct that the exact code you've tried won't work, you'll be able to use a very similar approach.
This code, for example, is cribbed directly from the app I'm working on right now in a class called RootViewController
that's (you guessed it) the app's root view controller:
public override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if NSProcessInfo.processInfo().environment["TESTING"] == nil {
loadChildren()
}
}
What it does is looks for an environment variable to decide if it should automatically continue with loading the app, and if it finds the environment variable it waits for the test stack to finish setting up and telling it what portion of the app to load next. (You could do this in your app delegate, too, if it's a really small app.)
You can set the environment variable by editing the scheme in Xcode:
All that said, though: take care when using this strategy. You want your tests to be testing features of your app as they exist in your app, and if showing different screens arbitrarily is a feature of your app, that's probably okay. But if you start writing code that makes your app behave differently when under test, you're not really testing your app anymore, are you?
Upvotes: 3