【发布时间】:2015-02-26 01:37:30
【问题描述】:
我正在尝试向我的项目中添加一些单元测试来测试视图控制器。但是,我似乎在看似简单的事情上遇到了问题。我创建了一个我将参考的示例项目。 https://github.com/pangers/ViewControllerTesting
示例包含一个 UINavigationController 作为初始视图控制器。 UINavigationController 的根视图控制器是 FirstViewController。 FirstViewController 上有一个连接到 SecondViewController 的按钮。在 SecondViewController 中有一个空文本字段。
我要添加的两个测试是:
1) 检查 FirstViewController 中的按钮标题是否为“下一屏”。
2) 检查 SecondViewController 中的 textfield 是否为空,""。
我听说将您的 swift 文件添加到主要目标和测试目标的报告不是一个好习惯。但最好将您想要在测试中访问的任何内容公开并将主要目标导入测试。这就是我所做的。 (我还将主要目标的“定义模块”设置为“是”,因为这也是我在几篇文章中读到的)。
在 FirstViewControllerTests 中,我使用以下内容实例化了第一个视图控制器:
var viewController: FirstViewController!
override func setUp() {
let storyboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))
let navigationController = storyboard.instantiateInitialViewController() as UINavigationController
viewController = navigationController.topViewController as FirstViewController
viewController.viewDidLoad()
}
我已经添加了测试:
func testCheckButtonHasTextNextScreen() {
XCTAssertEqual(viewController.button.currentTitle!, "Next Screen", "Button should say Next Screen")
}
同样,对于 SecondViewControllerTest,我已经使用:
var secondViewController:SecondViewController!
override func setUp() {
let storyboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))
let navigationController = storyboard.instantiateInitialViewController() as UINavigationController
let firstviewController = navigationController.topViewController as FirstViewController
firstviewController.performSegueWithIdentifier("FirstToSecond", sender: nil)
secondViewController = navigationController.topViewController as SecondViewController
secondViewController.viewDidLoad()
}
还有测试:
func testTextFieldIsBlank() {
XCTAssertEqual(secondViewController.textField.text, "", "Nothing in textfield")
}
他们都失败了,我不太确定为什么。我怀疑我实例化视图控制器的方式不正确。实例化视图控制器的最佳方法是使用故事板(就像它在现实生活中运行一样)?或者可以通过以下方式实例化:
var viewController = FirstViewController()
你们在 swift 中使用 TDD 和视图控制器有什么经验?
我在 XCode 6.1.1 中使用 Swift。
提前致谢。
已解决
好的,在考虑了 modocache 和 Mike Taverne 的答案后,我找到了我的解决方案,我学到了一些东西,我将在下面写下来。
1) 我公开了任何我想测试的类/方法/变量。我不需要将 swift 文件添加到测试目标。
2) 我只需要为“Main”目标(而不是“Test”目标或整个项目)设置“Defines Module”
3) 实例化storyboard时,bundle应该设置为nil而不是NSBundle(forClass: self.dynamicType),否则测试会失败。
4) 正如 modocache 所说,最好给你的视图控制器一个 StoryboardID 并像这样实例化它们:
viewController = storyboard.instantiateViewControllerWithIdentifier("FirstViewController") as FirstViewController
然而,像这样实例化视图控制器只会单独实例化视图控制器,而不是它可能嵌入的任何导航控制器。这意味着,尝试这样做
XCTAssertFalse(viewController.navigationController!.navigationBarHidden, "Bar should show by default")
将导致 nil 异常。我确认了这一点
XCTAssertNil(viewController.navigationController?, "navigation controller doesn't exist")
这导致了成功的测试。
由于我想在 FirstViewController 中检查导航栏的状态,你必须像这样实例化视图控制器:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navigationController = storyboard.instantiateInitialViewController() as UINavigationController
viewController = navigationController.topViewController as FirstViewController
现在进行测试
XCTAssertFalse(viewController.navigationController!.navigationBarHidden, "nav bar should be showing by default")
测试成功。
5) let _ = viewController.view 确实会触发 viewDidLoad() 已通过测试确认
6) let _ = viewController.view 不会触发 viewWillAppear(),然后我也假设任何事情。 viewController.viewWillAppear(false/true) 需要手动调用才能触发(经测试确认)。
希望这对人们有所帮助。如果有人想玩它,我会将更新的项目推送到 GitHub(上面的链接)。
更新 #2
经过以上所有操作,我仍然无法弄清楚如何从第一个视图控制器转换到第二个视图控制器(以便我可以在 SecondViewControllerTests.swift 中测试导航栏属性)。我试过了
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let nc = storyboard.instantiateInitialViewController() as UINavigationController
let firstVC = nc.topViewController as FirstViewController
firstVC.performSegueWithIdentifier("FirstToSecond", sender: nil)
secondVC = nc.topViewController as SecondViewController
导致错误。
我也试过了
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let nc = storyboard.instantiateInitialViewController() as UINavigationController
let firstVC = nc.topViewController as FirstViewController
firstVC.toSecondVCButton.sendActionsForControlEvents(UIControlEvents.TouchUpInside)
secondVC = nc.topViewController as SecondViewController
这不起作用。
我最终尝试了
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let nc = storyboard.instantiateInitialViewController() as UINavigationController
vc = storyboard.instantiateViewControllerWithIdentifier("Second") as SecondViewController
nc.pushViewController(vc, animated: false)
let _ = vc.view
vc.viewWillAppear(false)
这与我的测试完美配合(允许我访问导航栏属性)!
【问题讨论】:
-
很好地更新了您的发现。这对其他人有帮助。
标签: ios unit-testing swift uiviewcontroller tdd