mat*_*att 6

期待和等待是正确的。你只是用错了。

你想太多了。您不需要async测试方法。你不需要给fulfill自己打电话。您不需要组合链。只需使用谓词期望等待直到vm.result设置。

基本上规则是这样的:测试一个async方法需要一个async测试方法。但是测试碰巧进行异步调用的方法的异步“结果”,就像您的init方法一样,只需要良好的老式期望和等待测试。

我举个例子。这是您的代码的简化版本;该结构与您正在做的基本相同:

protocol Fetching {
    func fetch() async -> String
}
class MyClass {
    var result = ""
    init(fetcher: Fetching) {
        Task {
            self.result = await fetcher.fetch()
        }
    }
}

好的,下面是如何测试它:

final class MockFetcher: Fetching {
    func fetch() async -> String { "howdy" }
}

final class MyLibraryTests: XCTestCase {
    let fetcher = MockFetcher()
    func testMyClassInit() {
        let subject = MyClass(fetcher: fetcher)
        let expectation = XCTNSPredicateExpectation(
            predicate: NSPredicate(block: { _, _ in
                subject.result == "howdy"
            }), object: nil
        )
        wait(for: [expectation], timeout: 2)
    }
}

专家补充: Bool 谓词期望是一种常用的东西,手头有一个将期望、谓词和等待组合到一个包中的便捷方法会很有用:

extension XCTestCase {
    func wait(
        _ condition: @escaping @autoclosure () -> (Bool),
        timeout: TimeInterval = 10)
    {
        wait(for: [XCTNSPredicateExpectation(
            predicate: NSPredicate(block: { _, _ in condition() }), object: nil
        )], timeout: timeout)
    }
}

结果是,例如,上面的测试代码可以简化为:

    func testMyClassInit() {
        let subject = MyClass(fetcher: fetcher)
        wait(subject.result == "howdy")
    }

确实方便。在我自己的代码中,我经常添加一个显式断言,即使它完全是多余的,只是为了清楚地说明我声称我的代码做了什么:

    func testMyClassInit() {
        let subject = MyClass(fetcher: fetcher)
        wait(subject.result == "howdy")
        XCTAssertEqual(subject.result, "howdy") // redundant but nice
    }

更多推荐

测试,Swift,init