XCTKeyPathExpectation returns an unexpected error

162 views Asked by At

I've tried to use XCTKeyPathExpectation in an async environment and could not get it to work. The error I'm getting is confusing me a lot. Because the error stated is not really an error in my opinion...

I've created a very simple test to see if I did something wrong. Using the following two classes:

TestMock.swift:

import Foundation
@testable import UnitTests

final class TestMock: NSObject {
    @objc private(set) var testCalled: Bool = false

    func test() {
        self.testCalled = true
    }
}

UnitTestsTests.swift:

import XCTest
@testable import UnitTests

final class UnitTestsTests: XCTestCase {
    var testMock: TestMock!

    override func setUpWithError() throws {
        self.testMock = TestMock()
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDownWithError() throws {
        self.testMock = nil
        try super.tearDownWithError()
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    func testExample() throws {
        let expectation = XCTKeyPathExpectation(keyPath: \TestMock.testCalled,
                                                observedObject: self.testMock,
                                                expectedValue: true)
        self.testMock.test()
        self.wait(for: [expectation], timeout: 1.0)
    }
}

It gives me the error: testExample(): Asynchronous wait failed: Exceeded timeout of 1 seconds, with unfulfilled expectations: "Expect value of 'Swift.ReferenceWritableKeyPath<UnitTestsTests.TestMock, Swift.Bool>' of <UnitTestsTests.TestMock: 0x600003bfc090> to be 'true', was 'true'".

The only thing I can think of is that is comparing a Swift.Bool with an Objective-C Bool. But not sure how to fix this.

1

There are 1 answers

0
Robert Veringa On

It appears that I needed to add the word 'dynamic' to the declaration of testCalled.

@objc dynamic private(set) var testCalled = false