我正在尝试在我的iOS项目中加入UI测试,但是有一件事情继续让我感到震惊的是,你所编写的所有测试似乎都必须从应用程序的开头开始并逐步完成.例如,如果我想测试登录屏幕后面的视图,我的测试必须首先在登录屏幕上运行,输入用户名/密码,单击登录,然后转到我想要测试的视图.理想情况下,登录视图和下一个视图的测试将完全隔离.有没有办法做到这一点,还是我完全错过了UI测试背后的哲学?
绝对!
您需要的是一个干净的应用程序环境,您可以在其中运行测试 - 一个空白的平板.
所有应用程序都有一个应用程序委托,它设置应用程序的初始状态,并在启动时提供根视图控制器.出于测试目的,您不希望发生这种情况 - 您需要能够独立测试,而不会发生所有这些事情.理想情况下,您希望能够拥有屏幕,仅加载该屏幕,并且不会发生其他状态更改.
为此,您可以创建一个对象,仅用于测试该实现UIApplicationDelegate
.您可以告诉应用程序以"测试模式"运行,并使用启动参数使用特定于测试的应用程序委托.
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)) }
您必须@UIApplicationMain
从Swift类中删除任何注释.
对于"应用程序测试",请确保在Xcode中设置方案的"测试"操作以提供启动参数:
对于UI测试,您可以将启动参数设置为测试的一部分:
Objective-C的:
XCUIApplication *app = [[XCUIApplication alloc] init]; [app setLaunchArguments:@[@"org.quellish.UITestingEnabled"] ]; [app launch];
迅速:
let app = XCUIApplication() app.launchArguments = [ "org.quellish.UITestingEnabled" ] app.launch()
这允许测试特定地使用应用程序委托进行测试.这使您有了很多控制权 - 现在您可以使用空白板进行测试.测试应用程序委托可以加载特定的故事板或放置一个空的UIViewController
.作为UI测试的一部分,您可以实例化测试中的视图控制器并将其设置为keyWindow
根视图控制器或以模态方式呈现它.一旦添加或呈现,您的测试就可以执行,并在完成时删除或解除它.
如果您不介意原始UI加载,只需跳转到目标UI:
override func setUp() { super.setUp() continueAfterFailure = false XCUIApplication().launch() let storyboard = UIStoryboard(name: "MainStoryboard", bundle: NSBundle.mainBundle()) let controller = storyboard.instantiateViewControllerWithIdentifier("LanguageSelectController") UIApplication.sharedApplication().keyWindow?.rootViewController = controller }
如果你不想加载下面的原始UI,那么也要从你的测试中传入:
app.launchArguments.append("skipEntryViewController")
然后在didFinishLaunchingWithOptions
,你可以检查:
if NSProcessInfo.processInfo().arguments.contains("skipEntryViewController") { // then do NOT call makeKeyAndVisible }