我正在尝试在Swift中执行一些非常简单的功能/功能测试,但我有一些疑问,我需要解决才能创建有用的测试。
我想验证另一个Controller提供的Controller是否存在于应用程序导航层次结构中(如果Controller已经作为Modal或其他任何内容呈现在NavigationController中,则无关紧要)。
如果我以编程方式实例化并显示控制器,直接进入测试功能,当我检查 On Top控制器时,我总是得到 Storyboard 根控制器而不是控制器我刚刚实例化,好像我手动创建的控制器从未添加到应用程序层次结构中。
这是伪代码的一个例子:
func testController(){
// Instantiate a controller
let storyBoard:UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))
let controller1 = storyBoard.instantiateViewControllerWithIdentifier("Controller1") as? ControllerOneViewController
controller1.loadView()
// Call a function that instantiates another controller
controller1.pushAnotherController()
// Test that the current shown controller is what we expect...
let rootController = UIApplication.sharedApplication().keyWindow?.rootViewController
XCTAssert(rootController.self == TheExpectedClass, "Controller is not what we expect")
}
答案 0 :(得分:5)
如果我以编程方式实例化并显示控制器,直接进入测试功能,当我检查On Top控制器时,我总是得到Storyboard根控制器而不是我刚刚实例化的控制器,就像我手动控制器一样“创建”永远不会添加到“应用程序层次结构”中。
从您编写的代码中,您没有检查On Top控制器,但是您正在检查根视图控制器本身(它包含层次结构中的所有视图控制器,包括导航控制器),这就是为什么您总是得到故事板根视图控制器。要从视图控制器获得最顶层的控制器,您可以使用以下递归函数,该函数采用根视图控制器并返回其最顶层的控制器
func topMostController(rootViewController:UIViewController)->UIViewController{
if let viewController = rootViewController as? UINavigationController{
return topMostController(viewController.visibleViewController)
}
if let viewController = rootViewController.presentedViewController{
return topMostController(viewController)
}
return rootViewController
}
然后在你的测试函数中检查控制器该函数返回
func testController(){
// Instantiate a controller
let storyBoard:UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))
let controller1 = storyBoard.instantiateViewControllerWithIdentifier("Controller1") as? ControllerOneViewController
controller1.loadView()
// Call a function that instantiates another controller
controller1.pushAnotherController()
// Test that the current shown controller is what we expect...
let rootController = UIApplication.sharedApplication().keyWindow?.rootViewController
XCTAssert(topMostController(rootController) == TheExpectedClass, "Controller is not what we expect")
}
答案 1 :(得分:0)
首先,您说如果导航控制器显示视图并不重要。所以我创建了一个空的应用程序,其中navigationcontroller作为初始控制器和两个ViewControllers,第一个只是namend ViewController
,第二个是我的ViewControllerSecond
,这是你的TheExpectedClass
控制器。
首先要注意的是:如果使用NavigationController,rootController将始终是navigationController。那么,让我们检查一下,如果我们先加载ViewController
,然后在此推送中ViewControllerSecond
:
let storyBoard:UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))
let controllerSecond = storyBoard.instantiateViewControllerWithIdentifier("ViewControllerSecond") as? ViewControllerSecond
controllerSecond?.loadView()
self.navigationController?.pushViewController(controllerSecond!, animated: false)
let navigationController = UIApplication.sharedApplication().keyWindow?.rootViewController as UINavigationController
let currentController: AnyObject = navigationController.viewControllers[0]
println(navigationController.viewControllers)
您将看到ViewControllerSecond
被推送到navigationController。
答案 2 :(得分:0)
如果我以编程方式实例化并显示控制器,直接进入 测试功能,当我检查On Top控制器时,我总是得到 Storyboard根控制器而不是我拥有的控制器 刚刚实例化,就好像我手动创建的控制器一样 永远不会添加到应用程序层次结构中。
你在这里说的是真的,它们没有被添加。在您的伪代码中,您所做的只是实例化一些视图控制器并将它们相互推送。
为什么你期望它们出现在应用程序层次结构中?你从未在那里添加它们。
这里实际上有两个问题,那只是第一个问题。
第二个问题:
UIApplication.sharedApplication().keyWindow?.rootViewController
这段代码抓住了根视图控制器,它实际上就是那个位于底层"底部的控制器。 (假设"顶部"意味着更明显)。当您使用Storyboard时,这几乎总是初始视图控制器。
因此,即使您确实将新实例化的视图控制器添加到层次结构中,您所做的测试仍然无法通过。
建议的解决方案
作为一项简单的测试,您无需测试新的视图控制器是否位于可视层次结构之上。为此,您需要将其添加到那里。
你真正需要测试的是 - "如果我将我的视图控制器推到这个新创建的导航堆栈上,它应该位于该堆栈的顶部(可见)"
这样,您的测试不依赖于应用程序状态或层次结构中的任何其他控制器。
伪代码:
func testController(){
// Instantiate a controller
let storyBoard:UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))
let controller1 = storyBoard.instantiateViewControllerWithIdentifier("Controller1") as? ControllerOneViewController
controller1.loadView()
// Call a function that instantiates another controller
controller1.pushAnotherController()
// Test that the current shown controller is what we expect...
let nav = controller1.navigationController! //Assuming it's embedded in one
XCTAssert(nav.visibleViewController.self == TheExpectedClass, "Controller is not what we expect")
}