Home > OS >  Unit testing a defer statement within an async function
Unit testing a defer statement within an async function

Time:09-24

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() 
}
  • Related