Swift:测试 Segue 是否存在,是否有正确的目的地并更改正确的内容

标签 swift xcode

我是快速测试的新手,目前我想尝试四个测试。我有一个从 ViewController 到另一个 ViewController (searchedForViewController) 的 segue。对于这个 segue,我想测试这 4 件事:

  1. 是否存在标识符为“searchSegue”的 segue?
  2. 是否调用了 segue 然后我点击按钮搜索?
  3. Segue 的目的地是 SearchedForViewController
  4. Segue 是否将 SearchedForVC 的变量“passedString”更改为“garten”?

我在 Main.storyboard 中的 segue 看起来像这样:

Segue

我的 segue 代码如下(工作,但为了将来我只想知道如何测试):

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "searchSegue" {
            guard let controller = segue.destination as? SearchedForViewController 
        else {
                return
            }
                controller.passedString = "garten"
        }
    }

目前我的测试类是空的,看起来像这样(只是加载 View ):

class ViewControllerTests: XCTestCase {

    var vc: ViewController!

    override func setUp() {
        super.setUp()

        let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
        vc = storyboard.instantiateViewController(withIdentifier: "test") as! ViewController
        let _ = vc.view
    }

    func testSegueShouldExist() {
        let identifiers = getSegues(ofViewController: vc)
        XCTAssertEqual(identifiers.count, 1, "Segue count should equal one.")
        XCTAssertTrue(identifiers.contains("searchSegue"), "Segue searchSegue should exist.") 
    }

    func testSegueActionsThenPushSearchButton() {
        // code here  
    }

    func testSegueDirectsToSearchedForViewController() {
        // code here  
    }

    func testSeguePassedGartenAsValueToSearchedForVC() {
        // call prepare and test after? 
    }
}

编辑我发现了如何实现 segueShouldExist。我添加了代码。它调用辅助函数:

func getSegues(ofViewController viewController: UIViewController) -> [String] {
        let identifiers = (viewController.value(forKey: "storyboardSegueTemplates") as? [AnyObject])?.flatMap({ $0.value(forKey: "identifier") as? String }) ?? []
        return identifiers
    }

最佳答案

要使其正常工作,您需要稍微重构一下代码。

# ViewControllerTests.swift
var capturedSegue: UIStoryboardSegue?

extension ViewController {
    override open func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        prepareSearchForVC(with: segue)
        capturedSegue = segue
    }
}

class ViewControllerTests: XCTestCase {

    var vc: ViewController!

    override func setUp() {
        super.setUp()

        let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
        vc = storyboard.instantiateInitialViewController() as! ViewController
        vc.loadViewIfNeeded()
    }

    func testSegueShouldExist() {
        let identifiers = getSegues(ofViewController: vc)
        XCTAssertEqual(identifiers.count, 1, "Segue count should equal one.")
        XCTAssertTrue(identifiers.contains("searchSegue"), "Segue searchSegue should exist.")
    }

    func testSegueActionsThenPushSearchButton() {
        // Can programmatically send actions to UIControl classes
        vc.searchButton.sendActions(for: .touchUpInside)

        // Just makes sure any segue was called
        // since there is only one in this case there's no need to be more specific
        XCTAssertNotNil(capturedSegue) 
    }

    func testSegueDirectsToSearchedForViewController() {
        vc.performSegue(withIdentifier: "searchSegue", sender: nil)

        // Attempts to cast the captured segue
        let destination = capturedSegue?.destination as? SearchedForVC

        XCTAssertNotNil(destination,
                        "Destination should be searched for controller")
    }

    func testSeguePassedGartenAsValueToSearchedForVC() {
        vc.performSegue(withIdentifier: "searchSegue", sender: nil)

        let destination = capturedSegue?.destination as? SearchedForVC

        XCTAssertEqual(destination?.passedString, "garten")
    }

    func getSegues(ofViewController viewController: UIViewController) -> [String] {
        let identifiers = (viewController.value(forKey: "storyboardSegueTemplates") as? [AnyObject])?.flatMap({ $0.value(forKey: "identifier") as? String }) ?? []
        return identifiers
    }
}

使这项工作成功的原因是将 ViewController 中的 prepare(for:,sender:) 方法从:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "searchSegue" {
        guard let controller = segue.destination as? SearchedForViewController 
    else {
            return
        }
            controller.passedString = "garten"
    }
}

到:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    prepareSearchForVC(with: segue)
}

func prepareSearchForVC(with segue: UIStoryboardSegue) {
    if segue.identifier == "searchSegue" {
        guard let controller = segue.destination as? SearchedForVC
            else {
                return
        }
        controller.passedString = "garten"
    }
}

希望对您有所帮助。

关于Swift:测试 Segue 是否存在,是否有正确的目的地并更改正确的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42002019/

相关文章:

xcode - 如何检测 UITextField 中的阿拉伯字符?

ios - 选择器没有从从 firebase 提取的数组中获取数据

swift - 将 Etc/GMT 时间转换为 Swift Date() 全局时间

swift - Swift 中是否有前缀头(或具有此功能的东西)?

ios - 获取具有最近日期的对象

ios - 已辞职的 ipa 在 iOS 8 中安装但未在 iOS 9+ 中安装

ios - NSLayoutConstraint "Unable to simultaneously satisfy constraints"错误以及如何解释它们

ios - TabBarController 的自动布局问题

swift - .writeValue 不会让我将十六进制字符串写入特征以启用通知

ios - 如何将多个对象传递给延迟方法?