Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
718 views
in Technique[技术] by (71.8m points)

swift - iOS UI Testing On an Isolated View

I'm trying to incorporate UI tests in my iOS project, but one thing that continues to hold me up is the fact that it seems all of the tests you write must start from the beginning of the app and work their way through. For example, if I want to test a view that is behind a login screen, my tests must first run on the login screen, enter a username/password, click login, then go to the view I want to test. Ideally, the tests for the login view and the next one would be completely isolated. Is there a way to do this, or am I missing the philosophy behind UI tests completely?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Absolutely!

What you need is a clean application environment in which you can run your tests - a blank slate.

All applications have an application delegate which sets up the initial state of the application and provides a root view controller on launch. For the purposes of testing you don't want that to happen - you need to be able to test in isolation, without all of those things happening. Ideally you want to be able to have the screen undertest and only that screen loaded, and no other state changes happen.

To do so you can create an object just for testing that implements UIApplicationDelegate. You can tell the application to run in "testing mode" and use the testing-specific application delegate using a launch argument.

Objective-C: main.m:

int main(int argc, char * argv[]) {
NSString * const kUITestingLaunchArgument   = @"org.quellish.UITestingEnabled";

    @autoreleasepool {
        if ([[NSUserDefaults standardUserDefaults] valueForKey:kUITestingLaunchArgument] != nil){
            return UIApplicationMain(argc, argv, nil, NSStringFromClass([TestingApplicationDelegate class]));
        } else {
            return UIApplicationMain(argc, argv, nil, NSStringFromClass([ProductionApplicationDelegate class]));
        }
    }
}

Swift: main.swift:

let kUITestingLaunchArgument = "org.quellish.UITestingEnabled"

if (NSUserDefaults.standardUserDefaults().valueForKey(kUITestingLaunchArgument) != nil){
    UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(UIApplication), NSStringFromClass(TestingApplicationDelegate))

} else {
    UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(UIApplication), NSStringFromClass(AppDelegate))
}

You will have to remove any @UIApplicationMain annotation from your Swift classes.

For "application tests" be sure to set the "Test" action of the scheme in Xcode to provide the launch argument:

Xcode Scheme editor

For UI tests you can set the launch arguments as part of the test:

Objective-C:

XCUIApplication *app = [[XCUIApplication alloc] init];
[app setLaunchArguments:@[@"org.quellish.UITestingEnabled"] ];
[app launch];

Swift:

let app = XCUIApplication()
app.launchArguments = [ "org.quellish.UITestingEnabled" ]
app.launch()

This allows the tests to use an application delegate specificly for testing. This empowers you with a lot of control - you now have a blank slate to work with for testing. The testing application delegate can load a specific storyboard or put in place an empty UIViewController. As part of your UI tests you might instantiate the view controller under test and set it as the keyWindow's root view controller or present it modally. Once it has been added or presented your tests can execute, and when complete remove or dismiss it.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...