XCTest Async функция Swift

Аз съм съвсем нов в XCTest, структурирах кода си в Model, View, Controller

Така че контролерът ще вземе данни от модела и след като получи данни, контролерът ще актуализира изгледа. Така че имам моя контролер и гледам както следва

Контролер:

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

Преглед:

func refresh() {
    isViewLoaded = true
}

и ето го моят 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")
}

знам, че мога

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

но къде трябва да сложа expectation.fulfill()?

waitForExpectation(timeout: 5, handler: nil)

Всяка помощ се оценява. Благодаря


person wes. i    schedule 04.08.2020    source източник
comment
Трябва да се подиграете с контролера, така че вашият тест да получи манипулатора за завършване. Или направете модела си годен за тестване.   -  person matt    schedule 04.08.2020
comment
Целта ми е да тествам контролера, вече мога да тествам моя модел   -  person wes. i    schedule 04.08.2020


Отговори (1)


Имате нужда вашият loadData да има манипулатор на завършване и следователно да можете да уведомявате извикващите, когато асинхронната функция е завършена.

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

И след това във вашия тест направете expectation.fulfill в completion от 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")
}
person Dávid Pásztor    schedule 04.08.2020
comment
Благодаря, да, помислих си да направя моя loadData обратно извикване, просто си мисля дали това е най-добрата практика? Тъй като съм съвсем нов в init тестването, не съм сигурен дали е добре? - person wes. i; 04.08.2020
comment
По принцип това казах в коментара си. (Не е критика, просто казвам на OP.) С други думи, OP, ваша работа е да направите контролера годен за тестване, или самия него, или макетна версия. Можете да използвате инжектиране на зависимост, така че само тестваната версия да предоставя обратното извикване. - person matt; 04.08.2020
comment
@wes.i да, най-добрата практика е асинхронните методи да имат обратно извикване. И не само за тестване, а по принцип. - person Dávid Pásztor; 04.08.2020