I am having a defer
statement in my function that makes a server side request to get data. It is used to simply set the isLoading
variable to false
.
The thing is that I can not unit test that my method set the isLoading
variable to true
as the defer
statement is inevitably triggered, which is causing my unit test to fail.
Is there a way to avoid the defer statement in my unit test to make sure that my variable isLoading
is set?
var isLoading = false
func triggerServerSideRequest() async -> UserData {
isLoading = true
defer { isLoading = false }
let user = await serverSideRequest.getUser()
return user
}
func testServerSideRequest_requestIsTriggered_isLoadingIsTrue() async {
_ = await sut.triggerServerSideRequest()
let result = sut.isLoading
// defer statement set isLoading to false
// which cause my test to fail.
XCTAssertTrue(result)
}
CodePudding user response:
No, you can't test it, at least not in its current form. async/await make the code behave like a synchronous one, and if the synchronous form you couldn't have tested the isLoading
property also.
But all is not lost, because you still have a way out: inject serverSideRequest
, and have your unit tests not fulfil the async request until you've asserted.
protocol ServerSideRequest {
func getUser() async -> UserData
}
, and in your unit tests:
class TestServerSideRequest {
// this needs to be set before the call, otherwise, boom
var getUserResult: UserData!
// allow tests to execute code when `getUser` is called
var onGetUser: () -> Void = { }
func getUser() async -> UserData {
onGetUser()
return await withUnsafeContinuation {
$0.resume(returning: getUserResult)
}
}
}
func testServerSideRequest_requestIsTriggered_isLoadingIsTrue() async {
XCTAssertFalse(sut.isLoading)
testServerSideRequest.onGetData = {
XCTAssertTrue(sut.isLoading)
}
_ = await sut.triggerServerSideRequest()
}