独立视图上的iOS UItesting
我正在尝试在我的iOS项目中joinUItesting,但是有一件事仍然让我担心,看起来你写的所有testing都必须从应用程序的开始开始, 例如,如果我要testinglogin屏幕后面的视图,我的testing必须先在login屏幕上运行,input用户名/密码,单击login,然后转到我要testing的视图。 理想情况下,login视图和下一个视图的testing将完全隔离。 有没有办法做到这一点,或者我完全错过了UItesting背后的哲学?
绝对!
你需要的是一个干净的应用程序环境,你可以运行你的testing – 一个空白的石板。
所有应用程序都有一个应用程序委托,它设置应用程序的初始状态,并在启动时提供一个根视图控制器。 为了testing的目的,你不希望发生这种情况 – 你需要能够独立地进行testing,而不会发生所有这些事情。 理想情况下,您希望能够进行屏幕处理,只有该屏幕已加载,并且不会发生其他状态变化。
要做到这一点,你可以创build一个对象,只是为了实现UIApplicationDelegate
testing。 您可以让应用程序以“testing模式”运行,并使用启动参数使用特定于testing的应用程序委托。
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)) }
你将不得不从你的Swift类中删除任何@UIApplicationMain
批注。
对于“应用程序testing”,请务必在Xcode中设置scheme的“testing”行为来提供启动参数:
对于UItesting,您可以将启动参数设置为testing的一部分:
Objective-C的:
XCUIApplication *app = [[XCUIApplication alloc] init]; [app setLaunchArguments:@[@"org.quellish.UITestingEnabled"] ]; [app launch];
迅速:
let app = XCUIApplication() app.launchArguments = [ "org.quellish.UITestingEnabled" ] app.launch()
这允许testing使用特定的应用程序委托进行testing。 这使得你有很多的控制权 – 你现在有一个空白的板岩与testing工作。 testing应用程序委托可以加载特定的故事板或放置一个空的UIViewController
。 作为UItesting的一部分,你可以实例化testing下的视图控制器,并将其设置为keyWindow
的根视图控制器或以模态方式呈现。 一旦它被添加或呈现,您的testing可以执行,并在完成时删除或解雇它。
如果您不介意原始的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加载,那么也可以通过你的testing:
app.launchArguments.append("skipEntryViewController")
然后在didFinishLaunchingWithOptions
,可以检查:
if NSProcessInfo.processInfo().arguments.contains("skipEntryViewController") { // then do NOT call makeKeyAndVisible }
不幸的是,在UItesting中,你所描述的场景是不可能的。
我采取的一个方法是将我的testing分为特征stream。 例如,假设我想testingfunctionA,functionB和functionC.我需要login才能正常工作。
对于每个testing,我不启动应用程序,login,然后最后运行实际testing。 相反,我启动应用程序并login一次。 然后我将我的testing分成三个专用帮助方法, testFeatureA()
, testFeatureB()
和testFeatureC()
。
通过创build单一stream程,testing套件将花费更短的时间运行。 大的缺点是,如果functionA失败,那么functionB将永远不会被testing。 如果你关心所有的testing是否通过,只能使用这种方法。
使用带有__LINE__
和__FILE__
参数的XCTest帮助器的奖励点默认。 然后,您可以将这些传递给您的XCTFail()
调用,以显示testFeatureA()
上的失败行。