How to write unit test on async module

Hello,

If a module has async code and we want to perform unit test on it, the normal way will cause the async code to have no chance to execute.

Because the testing module is async so we have to waiting the async code complete and then do test assert.

We can use XCTestExpectation for that job.

Say SimilarPhotoScaner is an async photos scanner module, our testing code looks like here:

1 Add a scannerExpectation in test class.

class PhotoScannerTests: XCTestCase, SimilarPhotosScanerDelegate, PhotosScanerDelegate {
    
    var scannerExpectation: XCTestExpectation!

2 Waiting for the scannerExpectation in test method.

 func testSimilarPhotoScanning() throws {
        scannerExpectation = self.expectation(description: "Scaning")

        let scaner = SimilarPhotoScaner()
        // if we want to do a fast test, please give it a specify albumName
        scaner.albumName = "Cleaner"
        
        scaner.delegate = self
        scaner.similarPhotosScanerDelegate = self
        scaner.start()
     
        waitForExpectations(timeout: .infinity, handler: nil)
    }

In that case, SimilarPhotoScaner will start an async process in background DispatchQueue, the unit test code will be stuck and wait for the event.

3 Finally, we need to raise the event in delegate by call scannerExpectation.fulfill

    func onPhotoScanerCompleted(sender: PhotoScanerProtocol) {
        print( "test similar photos - complete" )
        scannerExpectation.fulfill()

    }

Then onPhotoScanerCompleted we will tell the unit test that scanner done.

So, with the unit test, you can test complex async component without have any UI.

Leave a Reply

Your email address will not be published. Required fields are marked *