Swift中的功能测试。模拟应用程序流程

时间:2014-12-07 20:46:23

标签: testing swift functional-testing

我正在尝试在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")
}

3 个答案:

答案 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")
}