Unit Tests III
Testing async code
Unit Tests III
Testing async code
0
0
Checkbox to mark video as read
Mark as read

When a unit test executes its line line of code the system finishes it and goes to the next test. This means that if we want to test asynchronous code, we need to indicate that our code is goinf to take some time.

We mainly have two types of asynchronous code to test, async code and closures, both of them need to be tested in different ways:

Async code

In case you need to test any async function, you can just mark your test as async as well. This allows you to call you functions asynchronously in order to wait for the result.

Let's imagine we have a ViewModel to test that returns a result asynchronously:

struct ViewModel {
    func fetchData() async throws -> Int {
        try await Task.sleep(nanoseconds: 1_000_000_000)
        return 5 // Just for demostration purposes
    }
}

Just mark your unit tests as async and wait for the result:

func testOne() async throws {
    let sut = ViewModel()

    let valueToTest = try await sut.fetchData()
    let expectedValue: Int = 5

    XCTAssertEqual(valueToTest, expectedValue)
}

Closures

In order to wait for a closure's result, we need to do some extra steps:

  • Create a XCTestExpectation instance.
  • Once we've done our asserts inside the closure, call .fulfill() function to indicate we've finished our test.
  • Call wait(for:) function to prevent our test to be finished until .fulfill() is called. You can pass multiple expectation here and it will wait until all of them are fulfilled. In addition, you can indicate a timeout to prevent waiting unnecesary time in case of failure.
struct ViewModel {
    func fetchData(completion: @escaping (Int) -> Void) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            completion(5) // Just for demostration purposes
        }
    }
}

func testOne() {
    let sut = ViewModel()

    let expectation: XCTestExpectation = expectation(description: "Wait for data fetching")

    sut.fetchData { result in
        let expectedValue: Int = 5
        XCTAssertEqual(result, expectedValue)

        expectation.fulfill()
    }

    wait(for: [expectation], timeout: 1)
}

0 Comments

Join the community to comment

Be the first to comment

Accept Cookies

We use cookies to collect and analyze information on site performance and usage, in order to provide you with better service.

Check our Privacy Policy