Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Unit testing Swift-涉及IBO的单元测试功能?_Unit Testing_Swift_Iboutlet - Fatal编程技术网

Unit testing Swift-涉及IBO的单元测试功能?

Unit testing Swift-涉及IBO的单元测试功能?,unit-testing,swift,iboutlet,Unit Testing,Swift,Iboutlet,我正在为我的Swift项目设置单元测试,在测试涉及更新IBOutlets的类函数时遇到了问题 我有一个函数validateUrl,它期望传递一个字符串,然后验证它。如果有效,则启用UIButton;如果无效,则禁用UIButton。当我运行调用此函数的测试时,应用程序在启用或禁用UIButton的代码行上崩溃。 故事板和控制器都有适当的测试目标集 这行代码: self.submitButton.enabled = true// Enable Submit Button 说出这个错误:

我正在为我的Swift项目设置单元测试,在测试涉及更新IBOutlets的类函数时遇到了问题

我有一个函数validateUrl,它期望传递一个字符串,然后验证它。如果有效,则启用UIButton;如果无效,则禁用UIButton。当我运行调用此函数的测试时,应用程序在启用或禁用UIButton的代码行上崩溃。 故事板和控制器都有适当的测试目标集

这行代码:

    self.submitButton.enabled = true// Enable Submit Button
说出这个错误:

fatal error: unexpectedly found nil while unwrapping an Optional value

您必须使用情节提要启动视图控制器。请参阅此处的文档:


如果您直接初始化视图控制器,它将不会有任何连接,因为VC本身不知道这种情况下的情节提要。

您可能需要在测试之前将控制器视图添加到层次结构中,以强制控制器加载XIB

let localContainer = UIView(frame:someFrame)
let controllerUnderTest = //instantiate your controller
localContainer.addSubview(controllerUnderTest.view)

//at this point you can test outlets

否则,您的插座将为零,因为它们尚未连接。

我用于在Swift中测试类的解决方案是在测试的setUp()方法中创建插座。例如,我有一个UIViewController子类,它将UIImageView作为一个出口。我声明了我的视图控制器子类的一个实例,该子类是我的测试类的一个属性,并通过初始化一个新的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对象,但视图控制器插座仍然为零).

请尝试以下代码来初始化视图控制器的IBOutlet:

   let yourStoryboard = UIStoryboard(name: "Your_storyboard", bundle: nil)
   yourViewController = yourStoryboard.instantiateViewController(withIdentifier: "YourViewController") as! YourViewController
   yourViewController.loadView() // This line is the key

@在您的例子中,talzag是nil,因为它们是弱变量,应该在实例化后立即解除分配

测试
IBOutlet
不是最好的方法,因为:

  • 应将门店视为实施细节,并应宣布为私人门店
  • 插座大部分时间连接到纯UI组件,单元测试处理测试业务逻辑
  • 测试由另一个功能注入到出口的值在某种程度上可以被视为集成测试。通过测试已连接/未连接的插座场景,您还需要加倍编写单元测试
在您的特定情况下,我建议改为测试验证器函数,但首先使其独立于控制器类(如果它还没有)。将该函数作为输入->输出函数还带来了其他好处,比如增加了可重用性

一旦您测试了验证器的所有可能场景,验证出口的行为是否正确,只需快速手动测试:只需检查出口的行为是否与验证器返回的行为相同。UI内容是手动测试的更好选择,因为手动测试也可以捕获其他细节(如位置、颜色等)


然而,如果您真的想测试插座行为,单元测试哲学中的一种技术就是快照测试。有一些库可用于此目的,我建议您使用。

您测试的是哪种类型的类?它是一个
UIViewController
子类吗?@iluvcapra-正确。该类是Swift中UIViewController的一个子类。我们可以使用nib执行同样的操作吗?这也可以通过简单地访问view属性来完成:=localController。view@Jan这并不意味着workloadView()帮了我的忙。我不必实例化我的故事板视图,因为它已连接到我以前的故事板VC。这应该是公认的答案。很好的答案!但是我不能理解这个验证器函数应该是什么样子。例如,我有一些逻辑将IBOutlet按钮设置为启用/禁用状态。正如你所说,我们不能(不应该)直接这样做。那么在这种情况下,我应该在这个验证器函数中测试什么呢。谢谢@例如,你可以有一个函数
func isSomethingAvailable()
,通过此函数的结果可以启用/禁用某些UI组件。