I'm trying to implement a network call using PromiseKit and if it fails I want it to retry several times before giving up. I have done this using the PromiseKit documentation and it seems to work well enough. However, I have encountered issue when trying to test my implementation.
This is what my test looks like:
func testFetch_withFirstAttemptFailed_shouldFetchEndpointFromDataProviderAgain() {
// Given
let expectation = self.expectation(description: "")
let failingAttempt = Promise<String>.pending()
let succeedingAttempt = Promise<String>.pending()
dataProviderMock.fetchReturnValues = [failingAttempt, succeedingAttempt]
let _: Promise<String> = sut.fetch(EndpointMock())
XCTAssertEqual(dataProviderMock.fetchInvokeCount, 1)
// When
failingAttempt.resolver.reject(MockError.error)
failingAttempt.promise.catch { (_) in
self.wait(for: 3)
succeedingAttempt.resolver.fulfill("success")
}
_ = succeedingAttempt.promise.done { [weak self] result in
// Then
XCTAssertEqual(result, "success")
guard let dataProvider = self?.dataProviderMock else { XCTFail(); return }
XCTAssertEqual(dataProvider.fetchInvokeCount, 2)
expectation.fulfill()
}
self.wait(for: [expectation], timeout: 4)
}
I have mocked my data provider to return different promises depending on which attempt it's currently trying. I want to check that fetch
is invoked a second time if the first attempt fails.
In particular I'm dissatisfied with the wait
part of the test but since I'm noob I don't know when to fulfill the succeeding attempt. My SUT has a retry delay of two seconds by default but I can inject another in my test if I wish. Ideally I don't want to wait at all so if anyone knows in what closure I can fulfill the succeeding attempt please let me know.
I've tried using the same recover
function used in the retry implementation but it seems that fulfilling it there executes the body before fetch is invoked so my assertion fails.