独立视图上的iOS UItesting

我正在尝试在我的iOS项目中joinUItesting,但是有一件事仍然让我担心,看起来你写的所有testing都必须从应用程序的开始开始, 例如,如果我要testinglogin屏幕后面的视图,我的testing必须先在login屏幕上运行,input用户名/密码,单击login,然后转到我要testing的视图。 理想情况下,login视图和下一个视图的testing将完全隔离。 有没有办法做到这一点,或者我完全错过了UItesting背后的哲学?

绝对!

你需要的是一个干净的应用程序环境,你可以运行你的testing – 一个空白的石板。

所有应用程序都有一个应用程序委托,它设置应用程序的初始状态,并在启动时提供一个根视图控制器。 为了testing的目的,你不希望发生这种情况 – 你需要能够独立地进行testing,而不会发生所有这些事情。 理想情况下,您希望能够进行屏幕处理,只有该屏幕已加载,并且不会发生其他状态变化。

要做到这一点,你可以创build一个对象,只是为了实现UIApplicationDelegatetesting。 您可以让应用程序以“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”行为来提供启动参数:

Xcode Scheme编辑器

对于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()上的失败行。