Centurion
Centurion

Reputation: 14304

Why GCD dispatch group notify is not called in Playground and Unit tests

I have the code working in simulator/device and I'm trying to write unit tests for it. However, notify callback is not called in unit tests. Here's is a code for Playgrounds which is also not calling notify callback. I suspect it I may be using the wrong queue, but cannot figure out which one I should use.

import UIKit

class Loader {

    func fetch(callback: ((_ result: String)-> Void)) {

        callback("SomeString")
    }
}

class MyService {

   var list: Array<String> = Array()
   var loader: Loader = Loader()
   var dispatchGroup = DispatchGroup()

    func loadList(callback: @escaping (()-> Void)) {

       for i in 1...3 {

           self.dispatchGroup.enter()

           self.loader.fetch(callback: { [weak self] (string) in

               self?.list.append(string)
               self?.dispatchGroup.leave()
           })
       }

       dispatchGroup.notify(queue: .main) {

           callback()
       }
   }
}

var service = MyService()
service.loadList {

    print("Done is not called")
}

UPDATE

Thanks to @paulvs, we need to enable indefinite execution. However, how to enable that for unit tests?

import UIKit
import PlaygroundSupport

class Loader {

    func fetch(callback: ((_ result: String)-> Void)) {

        callback("SomeString")
    }
}

class MyService {

    var list: Array<String> = Array()
    var loader: Loader = Loader()
    var dispatchGroup = DispatchGroup()

    func loadList(callback: @escaping (()-> Void)) {

        for i in 1...3 {

            self.dispatchGroup.enter()

            self.loader.fetch(callback: { [weak self] (string) in

                self?.list.append(string)
                self?.dispatchGroup.leave()
            })
        }

        dispatchGroup.notify(queue: .main) {

            callback()
        }
    }
}

PlaygroundPage.current.needsIndefiniteExecution = true

var service = MyService()
service.loadList {

    print("Done is called now!")
}

Upvotes: 3

Views: 2188

Answers (1)

Centurion
Centurion

Reputation: 14304

Thanks for the idea to @paulvs, and to this post, here's the code needed for unit tests:

let service = MyService()

let expect = expectation(description: "longRunningFunction")

service.loadList {

    expect.fulfill()
}

self.waitForExpectations(timeout: 0.5) { error in

    XCTAssert(service.isLoaded, "Not loaded")
}

Upvotes: 3

Related Questions