带有XCTestExpectation和NSPredicate的XCTWaiterwait似乎失败

问题描述

我正在尝试编写单元测试,以使我的测试用例等待某个类中的变量发生更改。因此,我用谓词创建了一个期望值,并等待使用XCTWaiter().wait(for: [expectation],timeout: 2.0)更改值,我认为这是可以使用的正确方法

以下代码按预期工作:

class ExpectationTests: XCTestCase {
var x: Int = 0

private func start() {
    _ = Timer.scheduledTimer(withTimeInterval: 0.5,repeats: false) { _ in
        self.x = 1
    }
}

func test1() {
    let predicate = nspredicate(format: "x == 1")
    let expectation = XCTnspredicateExpectation(predicate: predicate,object: self)
    start()
    let result = XCTWaiter().wait(for: [expectation],timeout: 2.0)
    switch result {
    case .completed:    XCTAssertEqual(x,1)
    case .timedOut:     XCTFail()
    default:            XCTFail()
    }
}

变量(x)设置为0,然后通过start()函数在0.5秒后变为1。谓词等待该变量(x)更改。可行:result设置为.completed,而var实际上设置为1。是的:-)

但是,当我要观察的变量不是局部变量,而是在某个地方的类中时,它将不再起作用。考虑以下代码片段:

class MyClass: NSObject {
    var y: Int = 0
    
    func start() {
        _ = Timer.scheduledTimer(withTimeInterval: 0.5,repeats: false) { _ in
            self.y = 1
        }
    }
}

func test2() {
    let myClass = MyClass()
    let predicate = nspredicate(format: "y == 1")
    let expectation = XCTnspredicateExpectation(predicate: predicate,object: myClass)
    myClass.start()
    let result = XCTWaiter().wait(for: [expectation],timeout: 2.0)
    switch result {
    case .completed:    XCTAssertEqual(myClass.y,1)
    case .timedOut:     XCTFail()
    default:            XCTFail()
    }
}

它与第一段代码非常相似,但这总是在2秒后结束,其中result.timedOut。我看不到我在做什么错。我使用了对象myClass中传递给期望值的变量,而不是局部变量和对象“ self”。 (测试结束时,类var myClass.y实际上设置为1。)

我尝试将XCTnspredicateExpectation(predicate:object)替换为expectation(for:evaluatedWith:handler),但这没什么区别。

StackOverflow上的许多示例都使用谓词来检查exists中的XCUIElement。但是我不是在测试UI。我只想检查某个类中的某些var是否在超时时间内更改了。我不明白为什么这与在exists中检查var XCUIElement有何不同。

有什么想法吗?!预先谢谢你!

解决方法

好吧,感谢@Willeke向我指出了正确的方向,我确实找到了解决方案,但是我不能说我完全理解它... 这是我的代码现在的样子:

// MARK: - Test 2
    class MyClass: NSObject {
        var y: Int = 0
        
        func start() {
            _ = Timer.scheduledTimer(withTimeInterval: 0.5,repeats: false) { _ in
                self.y = 1
            }
        }
    }
    
    func test2() {
        let myClass = MyClass()
        let predicate = NSPredicate() { any,_ in
//            guard let myClass = any as? MyClass else { return false }
            return myClass.y == 1
        }
        let expectation = XCTNSPredicateExpectation(predicate: predicate,object: myClass)
        myClass.start()
        let result = XCTWaiter().wait(for: [expectation],timeout: 2.0)
        switch result {
        case .completed:    XCTAssertEqual(myClass.y,1)
        case .timedOut:     XCTFail()
        default:            XCTFail()
        }
    }

我可以使用带闭包的谓词,该谓词可以定期检查var是否已更改,如果它具有正确的值,则返回true。 (大约每秒执行一次。)但是,实际上,考虑到XCTWaiter文档中的描述(这是expectation(for:evaluatedWith:handler:)的便捷方法),我实际上就是XCTNSPredicateExpectation的目的。 :

期望定期评估谓词。谓词评估为true时,该测试即可满足期望。

所以,我很高兴继续前进,但是我仍然不明白为什么这不适用于NSPredicate(format: "y == 1")而不是带有闭包的谓词...