如何测试视图控制器是否被解雇或弹出

时间:2019-01-29 09:30:09

标签: ios swift uikit

我想为我的函数编写一个单元测试,这是代码:

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

此方法自动选择关闭或弹出。那么,如何检查此功能后是否弹出或关闭了viewcontroller?谢谢你的帮助

6 个答案:

答案 0 :(得分:0)

您可以使用属性 self.isBeingPresented ,如果显示的是视图控制器,则将返回true;否则,如果按下则返回false。

答案 1 :(得分:0)

您可以使用以下方法检查viewControllers堆栈,并查看是否包含viewController:

self.navigationController.viewControllers

这将返回navigationController堆栈中包含的[UIViewController]

答案 2 :(得分:0)

您可以通过其for (const itm of item) { console.log(itm) } isBeingDismissed函数检查视图控制器的viewWillAppear属性。

请参见https://developer.apple.com/documentation/uikit/uiviewcontroller/2097562-isbeingdismissed

答案 3 :(得分:0)

我个人会使用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)符合您的期望就可以。

答案 4 :(得分:0)

我以这种方式解决了。我需要测试一个包含以下内容的简单方法:dismiss(animated: true, completion: nil),并制作了一个临时模拟了一个模拟viewController的临时模拟程序,该程序对我的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))
          }

我希望能有所帮助,我在这里毫无疑问。

答案 5 :(得分:0)

func smartBack(动画: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)
            }
}