我正在为我的Swift项目设置单元测试,并且无法测试涉及更新IBOutlets的类函数。
我有一个函数validateUrl,它希望传递一个字符串,然后验证它。如果它有效,则启用UIButton,如果它无效,则禁用UIButton。当我运行调用此函数的测试时,应用程序在启用或禁用UIButton的代码行上崩溃。 故事板和控制器都具有适当的测试目标集。
这行代码:
self.submitButton.enabled = true// Enable Submit Button
吐出此错误:
fatal error: unexpectedly found nil while unwrapping an Optional value
答案 0 :(得分:8)
您必须使用故事板启动视图控制器。请参阅此处的文档:https://developer.apple.com/library/ios/documentation/uikit/reference/UIStoryboard_Class/index.html#//apple_ref/occ/instm/UIStoryboard/instantiateViewControllerWithIdentifier:
如果直接初始化视图控制器,它将没有任何连接,因为在这种情况下VC本身不知道故事板。
答案 1 :(得分:6)
尝试使用此代码初始化视图控制器的IbOutlets:
let yourStoryboard = UIStoryboard(name: "Your_storyboard", bundle: nil)
yourViewController = yourStoryboard.instantiateViewController(withIdentifier: "YourViewController") as! YourViewController
yourViewController.loadView() // This line is the key
答案 2 :(得分:2)
您可能需要在测试之前将控制器视图添加到层次结构以强制控制器加载XIB
let localContainer = UIView(frame:someFrame)
let controllerUnderTest = //instantiate your controller
localContainer.addSubview(controllerUnderTest.view)
//at this point you can test outlets
否则您的网点将为零,因为它们尚未连接。
答案 3 :(得分:1)
我用来测试Swift中的类的解决方案是在测试的setUp()方法中创建出口。例如,我有一个UIViewController子类,它有一个UIImageView作为插座。我声明我的View控制器子类的一个实例是我的测试类的属性,&通过初始化一个新的UIImageView在setUp()方法中配置它的出口。
var viewController = ViewController() // property on the test class
override func setUp() {
super.setUp()
viewController.imageView = UIImageView(image: UIImage(named: "Logo")) // create a new UIImageView and set it as the outlet object
}
任何其他出口都可以类似地在setUp方法中设置,这样你甚至不必实例化故事板(出于某种原因,尽管我能够实例化一个UIStoryboard对象我的测试,视图控制器出口仍然没有。)
答案 4 :(得分:0)
@talzag在您的情况下,iboutlet为零,因为它们是弱变量,应该在实例化后立即取消分配。
答案 5 :(得分:0)
测试IBOutlet
并不是最好的方法,因为:
在您的特定情况下,我建议改为测试验证器功能,但首先使其独立于控制器类(如果尚未使用)。将该功能用作输入/输出功能还带来了其他好处,例如提高了可重用性。
测试了验证程序的所有可能情况之后,验证插座是否正常运行,只需进行快速手动测试即可:只需检查插座的行为是否类似于返回的验证程序。 UI内容更适合进行手动测试,因为手动测试也可以捕获其他细节(例如位置,颜色等)。
但是,如果您真的想测试出口行为,那么一种属于单元测试原理的技术就是快照测试。有一些可用的库,我推荐https://github.com/uber/ios-snapshot-test-case/中的库。