如何测试是否正确调用了deinit?

时间:2019-10-09 11:55:03

标签: ios swift

这是我的单元测试:

    func testDeinit() {
        let view = DocumentsView(theme: MockTheme())
        let viewModel = DocumentsViewModelMock()
        let delegate = DocumentsViewControllerDelegateMock()
        var controller: DocumentsViewController? = DocumentsViewController(view: view, viewModel: viewModel, delegate: delegate)
        controller?.viewDidLoad()
        let expectation = self.expectation(description: "")
        XCTAssertFalse(delegate.documentViewControllerDeinitializedWasCalled)
        controller = nil
        XCTAssertTrue(delegate.documentViewControllerDeinitializedWasCalled)
    }

deinit看起来像这样:

deinit {
    delegate?.documentViewControllerDeinitialized()
}

和我的代表:

class DocumentsViewControllerDelegateMock: DocumentsViewControllerDelegate {
    var documentViewControllerDeinitializedWasCalled = false
    func documentViewControllerDeinitialized() {
        documentViewControllerDeinitializedWasCalled = true
    }
}

我对DocumentsViewController的初始化。

    private weak var delegate: DocumentsViewControllerDelegate?
    // MARK: - Initialization
    init(view: DocumentsView, viewModel: DocumentsViewModelable, delegate: DocumentsViewControllerDelegate) {
        self.mainView = view
        self.viewModel = viewModel
        self.delegate = delegate
        super.init(nibName: nil, bundle: nil)
    }

上面的单元测试失败。为什么?

这种情况是因为检查了deinit的名称为 AFTER 。异步方式怎么做?

3 个答案:

答案 0 :(得分:1)

恕我直言,这是一个糟糕的测试。

您基本上是在测试如果对象已释放,则deinit中的内容是否被调用。那不是您要测试的东西。苹果的Swift设计师应该对此进行测试。

请另外做两个测试。

  1. 测试以查看在执行controller = nil之后是否已释放控制器。您可以只执行XCTAssertNil。诀窍是获取对控制器的weak引用,以便将其传递给assert
  2. 在一个孤立的问题中测试deinit方法内部的内容。在 您的情况将是手动触发 delegate?.documentViewControllerDeinitialized() + XCTAssertTrue(delegate.documentViewControllerDeinitializedWasCalled)

通过这种方式,您还可以避免嘲笑DocumentsViewControllerDelegate协议。

答案 1 :(得分:0)

在初始化delegate之后,单元测试中的DocumentsViewController很可能会立即解除分配。这是因为此后不再有对委托的更强引用,控制器中只有weak个引用。因此,控制器不再具有委托来调用deinit。

尝试延长代表的寿命,例如通过对其进行虚拟断言(例如XCTAssertEquals(controller.delegate, delegate)

答案 2 :(得分:-2)

您真的需要使用deinit方法吗?

  

在实例解除分配发生之前,会自动调用反初始化器。您不允许自己调用反初始化器。超类反初始化器由其子类继承,并且超类反初始化器在子类反初始化器实现的末尾自动调用。即使子类不提供自己的反初始化器,也总是调用超类反初始化器。

     

Blockquotee因为在取消调用实例之前,实例不会被释放,所以取消初始化程序可以访问其实例的所有属性,并可以基于这些属性修改其行为(例如查找所需文件的名称)关闭)。

来自https://docs.swift.org/swift-book/LanguageGuide/Deinitialization.html

相关问题