wes. i
wes. i

Reputation: 628

XCTest Async Function Swift

i'm quite new to XCTest, i have structured my code in Model, View, Controller

So controller will take data from Model and once got data, Controller will update View. So i have my Controller and view as follow

Controller:

func loadData() {
    Model.provideData { response in
        if response != nil {
            view.refresh()
        }
    }
}

View:

func refresh() {
    isViewLoaded = true
}

and here is my XCTest

func testLoadData() {
    let sut = Controller()
    let mockView = View()
    mockView.setController(controller: sut)
    controller.loadData()
    /** HERE is the problem, because it is a ASYNC call, i need to wait for the flag is set **/
    XCTAssertTrue(mockView.isViewLoaded, "isViewLoaded equals to true")
}

i know i can

let expectation = expectation(description: "wait for isViewLoaded set to true")

but where should i put the expectation.fulfill()?

waitForExpectation(timeout: 5, handler: nil)

Any help is appreciated. Thanks

Upvotes: 1

Views: 270

Answers (1)

David Pasztor
David Pasztor

Reputation: 54745

You need your loadData to have a completion handler and hence be able to notify its callers when the async function is complete.

func loadData(completion: @escaping () -> Void) {
    Model.provideData { response in
        if response != nil {
            view.refresh()
        }
        completion()
    }
}

And then in your test, do expectation.fulfill in the completion of loadData.

func testLoadData() {
    let expectation = expectation(description: "wait for isViewLoaded set to true")
    let sut = Controller()
    let mockView = View()
    mockView.setController(controller: sut)
    controller.loadData {
        expectation.fulfill()
    }
    waitForExpectation(timeout: 5, handler: nil)
    XCTAssertTrue(mockView.isViewLoaded, "isViewLoaded equals to true")
}

Upvotes: 2

Related Questions