Testing with async/await

Not long time ago I began journey transitioning from traditional imperative programming to functional way. Advantage of the functional programming is less code and less mutable states. It involved refactoring, and because I have limited time, I thought that adding unit tests will help me in maintaining my projects. I will write about my journey and lessons I learned as it helps me and hopefully will help you, dear reader.

One of problems I faced is with initialising my data model.

Async await testing.

View model values are not populated at the time of assertion because I use main thread dispatcher in my implementation of the loadViewModel function.

func loadViewModel() {
    Task {
        let appModel = self.pinbookModel
        await MainActor.run {
            self.viewModel = appModel
        }
    }
}

Remember await keyword is not blocking and assertion runs before pins and tags are populated.

I have started to notice the test passing sometimes with await task.value additional line:

func testAddPin() async {
    let database = self.newTestDatabase()

    let task = Task {
        await database.loadViewModel()
    }
    await task.value

    let pins = await database.viewModel.pins
    let tags = await database.viewModel.tags
    XCTAssertEqual(pins.count, 3)
    XCTAssertEqual(tags.count, 2)
}

Above passing for me only sometimes, not acceptable. I had to do more changes so the test now passes every time I run it.

func testAddPin() {
    let database = self.newTestDatabase()

    let task = Task {
        await database.loadViewModel()
    }
    Task {
        await task.value
        let pins = await database.viewModel.pins
        let tags = await database.viewModel.tags
        XCTAssertEqual(pins.count, 3)
        XCTAssertEqual(tags.count, 2)
    }
}

If you need more guidance writing your first async/await project and you not sure how to structure your code. I recommend this sample project from Apple: CloudKit Samples: CKSyncEngine.