[英]deinit called in app but not in unit test when dismissing view controller
我试图对视图控制器的内存进行单元测试,以查看它们在被关闭时是否正确地初始化。
class SettingsViewControllerTests: XCTestCase {
var controller: SettingsViewController!
override func setUp() {
super.setUp()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
controller = storyboard.instantiateViewController(withIdentifier: "SettingsViewController")
as? SettingsViewController
//load view hierarchy
_ = controller.view
}
func testLogout() {
let sideMenu = MockSideMenuViewController()
var navController: UINavigationController? = UINavigationController(rootViewController: sideMenu)
sideMenu.show(navController!, sender: nil)
navController?.pushViewController(controller, animated: true)
expect(navController).toNot(beNil())
controller.dismiss(animated: false, completion: nil)
expect(navController).toEventually(beNil(), timeout: 3) // fails
expect(self.controller).toEventually(beNil(), timeout: 3) // fails
}
在应用程序中,我使用segue展示了我的导航控制器+ SettingsViewController。 它有一个自身调用dismiss
的方法,但是当我检查控制器实例时,它们仍然存在。 在我的视图控制器中,我设置了一条打印语句,以检查是否正在调用deinit,当我执行应用程序中的步骤时,确实会调用它(两个控制器最终都变为nil
)。 但是,单元测试不能做到这一点。 我想念什么?
controller
是一个强烈持有的属性,因此您的测试将保留它。 现在,它仅在随后对setUp()
调用中被取消初始化。 如果要专门测试controller.deinit
,请在测试中执行controller = nil
。
您可能会执行以下操作:
var controller: SettingsViewController! // <--- this is a strong ref
func testLogout() {
let sideMenu = MockSideMenuViewController()
// navController is a strong ref, held until the end of the scope; don't expect it to be nil
var navController: UINavigationController? = UINavigationController(rootViewController: sideMenu)
sideMenu.show(navController!, sender: nil)
navController?.pushViewController(controller, animated: true)
// hold a weak ref to your controller and then nil out its reference
weak var weakController = controller
// remove the strong reference
controller = nil
// popping will release the last reference
navController?.popViewController(animated: false)
expect(weakController).to(beNil(),) // succeeds
}
一些注意事项:
navController
是作用域级别的变量。 直到函数结束才为零,因此没有理由进行测试或期望。 创建它之后,它肯定也不会为零。
UIViewController.dismiss(...)用于消除模态。 您的控制器是导航堆栈的一部分。 开除将不会达到您的期望。
感觉就像您在期待var navController: UINavigationController?
变得虚弱,但事实并非如此。 weak
var和属性应该是Optional
,但是可选并不意味着weak
。 请参阅弱引用 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.