查看控制器TDD [英] View Controller TDD

查看:93
本文介绍了查看控制器TDD的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试向我的项目中添加一些单元测试以测试视图控制器.但是,我似乎在看似简单的事情上遇到了问题.我已经创建了一个示例项目,我将参考它. https://github.com/pangers/ViewControllerTesting

I am trying to add some unit tests to my project to test view controllers. However I seem to be having problems with seemingly simple things. I have created a sample project which I will refer to. https://github.com/pangers/ViewControllerTesting

该示例包含一个UINavigationController作为初始视图控制器. UINavigationController的根视图控制器是FirstViewController.在FirstViewController上有一个按钮可以连接到SecondViewController.在SecondViewController中,有一个空的文本字段.

The sample contains a UINavigationController as the initial view controller. The root view controller of the UINavigationController is FirstViewController. There is a button on FirstViewController that segues to SecondViewController. In SecondViewController there is an empty textfield.

我要添加的两个测试是:
1)在FirstViewController中检查按钮标题为下一屏".
2)检查SecondViewController中的文本字段是否为空,".

The two tests I am trying to add are:
1) Check button title in FirstViewController is "Next Screen".
2) Check textfield in SecondViewController is empty, "".

我听说有报告将您的swift文件同时添加到主要目标和测试目标不是一个好习惯.但是,最好公开测试中要访问的所有内容,并将主要目标导入测试中.这就是我所做的. (我还将主要目标的定义模块"设置为是",因为这也是我在几篇文章中所读到的内容.)

I have heard reports of adding your swift files to both the main target and the test target is not good practice. But rather it is better to make whatever you want to access in your tests public and import the main target into the tests. So that is what I have done. (I have also set the "Defines Module" for the main target to YES as that is what I have read in a few articles aswell).

在FirstViewControllerTests中,我使用以下实例化了第一个视图控制器:

In FirstViewControllerTests I have instantiated the first view controller with the following:

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,我使用以下方法进行设置:

Similarly, for SecondViewControllerTest, I have set it up using:

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

它们都失败了,我不太确定为什么.我怀疑我实例化视图控制器的方式是不正确的.实例化视图控制器的最佳方法是使用情节提要(就像在现实生活中一样)吗?还是可以接受通过以下方式进行实例化:

They both fail and I am not too sure as to why. My suspicion is that the way I am instantiating the view controllers is not correct. Is the best way to instantiate the view controllers is to use the storyboard (just like it would if it were to run in real life)? Or is it acceptable to be instantiated via:

var viewController = FirstViewController()

你们在TDD和快速查看控制器方面有什么经验?

What are you guys' experience with TDD and view controllers in swift?

我正在使用带有XCode 6.1.1的Swift.

I am using Swift with XCode 6.1.1.

谢谢.

已解决

好了,在考虑了modocache和Mike Taverne的回答后,我找到了解决方案,并且学到了一些东西,我将在下面写下.

Ok after considering the answers from modocache and Mike Taverne, I've found my solution and I've learnt a few things which I will write down below.

1)我公开了要测试的任何类/方法/变量.我不需要将swift文件添加到测试目标.

1) I made anything class/method/variable that I want to test public. I do not need to add the swift files to the test target.

2)我只需要为主要"目标(而不是测试"目标或整个项目)设置定义模块"

2) I only needed to set "Defines Module" for the "Main" target (as opposed to the "Test" target or the entire project)

3)实例化情节提要时,应将捆绑软件设置为nil而不是NSBundle(forClass:self.dynamicType),否则测试将失败.

3) When instantiating the storyboard, the bundle should be set to nil rather than NSBundle(forClass: self.dynamicType), otherwise tests will fail.

4)正如modocache所说,最好为您的视图控制器提供一个StoryboardID并实例化它们,如下所示:

4) As modocache stated, it is good to give your view controller's a StoryboardID and instantiate them like so:

viewController = storyboard.instantiateViewControllerWithIdentifier("FirstViewController") as FirstViewController

但是,像这样实例化视图控制器只能单独实例化视图控制器,而不能实例化它可能嵌入的任何导航控制器.这意味着尝试这样做

However, instantiating the view controller like this ONLY instantiates the view controller alone, and not any navigation controllers that it may be embedded in. That means, attempting to do

XCTAssertFalse(viewController.navigationController!.navigationBarHidden, "Bar should show by default")

将导致nil异常.我用

will result in a nil exception. I confirmed this with

XCTAssertNil(viewController.navigationController?, "navigation controller doesn't exist")

这导致测试成功.

由于我要检查FirstViewController中导航栏的状态,因此必须像这样实例化视图控制器:

Since I wanted to check the state of the navigation bar in FirstViewController, you must instantiate the view controller like so:

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)让_ = viewController.view确实触发了经测试确认的viewDidLoad()

5) let _ = viewController.view does indeed trigger viewDidLoad() which was confirmed by a test

6)让_ = viewController.view不会触发viewWillAppear(),之后我也想一下.需要手动调用viewController.viewWillAppear(false/true)来触发它(由测试确认).

6) let _ = viewController.view does not trigger viewWillAppear(), and I presume anything afterwards aswell. viewController.viewWillAppear(false/true) needs to be called manually to trigger it (Confirmed by a test).

希望这会对人们有所帮助.如果有人想玩的话,我会将更新后的项目推送到GitHub(上面的链接).

Hopefully this will be of help to people. I will push the updated project to GitHub (link above) if anyone would like to play around with it.

更新#2

以上所有内容之后,我仍然不知道如何从第一个视图控制器过渡到第二个视图控制器(以便可以在SecondViewControllerTests.swift中测试导航栏属性).我尝试过

After all the above, I still could not figure out how to transition from the first view controller to the second view controller (so that I may test navigation bar properties in SecondViewControllerTests.swift). I tried

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)

与我的测试完美配合(允许我访问导航栏属性)!

which worked perfectly with my tests (allowed me to access navigation bar properties)!

推荐答案

我同意@MikeTaverne的回答:我更喜欢访问-[UIViewController view]来触发-[UIViewController viewDidLoad],而不是直接调用它.看看使用FirstViewController的测试失败是否可以消失:

I agree with @MikeTaverne's answer: I prefer accessing -[UIViewController view] in order to trigger -[UIViewController viewDidLoad], rather than calling it directly. See if the test failures for FirstViewController go away once you use this instead:

viewController = navigationController.topViewController as FirstViewController
let _  = viewController.view

我还建议您在情节提要中为两个视图控制器提供标识符.这将允许您直接实例化它们,而无需通过UINavigationController:

I'd also recommend giving both view controllers identifiers in your storyboard. This will allow you to instantiate them directly, without accessing them via UINavigationController:

var secondViewController: SecondViewController!

override func setUp() {
    let storyboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))
    secondViewController = storyboard.instantiateViewControllerWithIdentifier("SecondViewController")
        as SecondViewController
    let _ = secondViewController.view
}

在布鲁克林Swift上查看我关于测试UIViewController的演讲,以了解详细信息: https://vimeo.com/115671189#t= 37m50s (我的演讲开始于37'50左右).

Check out my talk on testing UIViewController at Brooklyn Swift for details: https://vimeo.com/115671189#t=37m50s (my presentation begins around the 37'50" mark).

这篇关于查看控制器TDD的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆