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

laximzn5  于 2022-12-24  发布在  iOS
关注(0)|答案(7)|浏览(317)

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

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

这个方法会自动选择dismiss或pop。那么,我如何检查这个函数之后viewcontroller是否弹出或被取消呢?谢谢你的帮助

d8tt03nd

d8tt03nd1#

您可以在视图控制器的viewWillAppearviewDidAppear函数中检查其isBeingDismissed属性。
参见https://developer.apple.com/documentation/uikit/uiviewcontroller/2097562-isbeingdismissed

yptwkmov

yptwkmov2#

func smartBack(动画:布尔值=真)将为:

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

gab6jxml3#

您可以使用属性self.isBeingPresented,如果视图控制器已显示,则返回true,否则如果已推送,则返回false。

bvjxkvbb

bvjxkvbb4#

您可以使用以下命令检查viewControllers堆栈并查看是否包含您的viewController:
第一个月
这将返回navigationController堆栈中包含的[UIViewController]

ekqde3dh

ekqde3dh5#

就我个人而言,我会使用Mocks来跟踪某些方法何时被调用。
您可以这样做:

class MockNavigationController: UINavigationController {

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

这样,无论何时你的代码调用popViewController,_popCalled的值都会被更新,但它实际上不会弹出任何东西,所以你可以Assert_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方法,这两个方法在任何一种情况下都会被调用。在你的单元测试中,你只需要Assertstubbed值(_popCalled)是真还是假。

bksxznpy

bksxznpy6#

我用这种方法解决了这个问题。我需要测试一个简单的方法,其中包含:dismiss(animated: true, completion: nil),我做了一个临时模拟,模拟一个viewController,它对我的主控制器进行推送,我在主控制器中应用disdissView。

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))
          }

我希望能有所帮助,我在这里对任何疑问。

c0vxltue

c0vxltue7#

这是为我工作:

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

相关问题