簡體   English   中英

如何測試視圖控制器是否被關閉或彈出

[英]How to test if view controller is dismissed or popped

我想為我的功能寫一個單元測試,這里是代碼:

  func smartBack(animated: Bool = true) {
    if isModal() {
      self.dismiss(animated: animated, completion: nil)
    } else {
      self.navigationController?.popViewController(animated: animated)
    }
  }

該方法自動選擇 dismiss 或 pop。 那么,我如何檢查 viewcontroller 在此功能之后是否彈出或關閉? 謝謝你的幫助

您可以在viewWillAppearviewDidAppear函數中檢查視圖控制器的isBeingDismissed屬性。

請參閱https://developer.apple.com/documentation/uikit/uiviewcontroller/2097562-isbeingdismissed

您可以使用屬性self.isBeingPresented ,如果視圖控制器呈現則返回 true 否則返回 false 如果推送。

您可以使用以下命令檢查 viewControllers 堆棧並查看是否包含您的 viewController:

self.navigationController.viewControllers

這將返回一個包含在 navigationController 堆棧中的[UIViewController]

我個人會使用 Mocks 來跟蹤何時調用某些方法。

你可以這樣做:

class MockNavigationController: UINavigationController {

    var _popCalled: Bool = false
    override func popViewController(animated: Bool) -> UIViewController? {
        _popCalled = true
        return self.viewControllers.first
    }
}

然后,無論何時您的代碼調用 popViewController, _popCalled值都會更新,但實際上不會彈出任何內容。 因此,您可以斷言_popCalled值以確保預期的調用發生。

這使得測試預期的事情發生變得容易,並且還可以防止您在測試中運行實際代碼。 這種方法很容易是一個服務調用,或者數據庫更新,設置一個標志等,所以可以更安全。

不過,它們一開始可能很難理解。 我建議在大量使用之前閱讀它們。

游樂場中的完整示例:

import UIKit
import PlaygroundSupport
import MapKit

class ClassUnderTest: UIViewController {
    var isModal: Bool = false

    func smartBack(animated: Bool = true) {
        if isModal {
            self.dismiss(animated: animated, completion: nil)
        } else {
            self.navigationController?.popViewController(animated: animated)
        }
    }
}

class MockNavigationController: UINavigationController {

    var _popCalled: Bool = false
    override func popViewController(animated: Bool) -> UIViewController? {
        _popCalled = true
        return self.viewControllers.first
    }
}

class MockClassUnderTest: ClassUnderTest {

    var _mockNavigationController = MockNavigationController()
    override var navigationController: UINavigationController? {
        return _mockNavigationController 
    }

    var _dismissCalled: Bool = false
    override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
        _dismissCalled = true
    }

}

var subject = MockClassUnderTest()
subject.isModal = true
subject.smartBack();
var navigation = subject.navigationController as! MockNavigationController

print(subject._dismissCalled)
print(navigation._popCalled)

輸出

true
false

subject = MockClassUnderTest();
subject.isModal = false
subject.smartBack();
navigation = subject.navigationController as! MockNavigationController

print(subject._dismissCalled)
print(navigation._popCalled)

輸出

false
true

在本例中,您將覆蓋在任何一種情況下都會調用的dismiss 和pop 方法。 在您的單元測試中,您只需根據您的期望斷言存根值 (_popCalled) 是真還是假。

我是這樣解決的。 我需要測試一個包含以下內容的簡單方法: dismiss(animated: true, completion: nil)並且我制作了一個時間模擬來模擬一個視圖控制器,該視圖控制器對我的 MainController 進行推送,這是我應用dismissView 的地方。

 func testValidatesTheDismissOfViewController() {
            // Given
            let mockViewController: UIViewController = UIViewController()
            let navigationController = UINavigationController(rootViewController: mockViewController)
// Create instance of my controller that is going to dismiss.
            let sut: HomeWireFrame = HomeWireFrame().instanceController()
            navigationController.presentFullScreen(sut, animated: true)
            // When
            sut.loadViewIfNeeded()
            sut.closeView()
            // Create an expectation...
            let expectation = XCTestExpectation(description: "Dismiss modal view: HomeViewController")
            // ...then fulfill it asynchronously
            DispatchQueue.main.async { expectation.fulfill() }
            wait(for: [expectation], timeout: 1)
            // Then - if its different of my home controller
            XCTAssertTrue(!(navigationController.topViewController is HomeViewController))
          }

我希望能有所幫助,我在這里有任何疑問。

func smartBack(animated: Bool = true) 將是:

func smartBack(animated: Bool = true) {  
  if self.navigationController?.viewControllers.first == self {
                self.dismiss(animated: animated, completion: nil)
            } else {
                self.navigationController?.popViewController(animated: true)
            }
}

它對我有用:

func smartBack(animated: Bool = true) {
            if self.navigationController == nil {
                self.dismiss(animated: animated, completion: nil)
            } else {
                self.navigationController?.popViewController(animated: true)
            }
        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM