Here is my downloading function:
// Download a file from the url to the local directory
class func downloadUrl(url: URL, to dirUrl: URL, completion: (() -> ())?){
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = URLRequest(url: url)
let task = session.downloadTask(with: request) {(tempLocalUrl, response, error) in
if let tempLocalUrl = tempLocalUrl, error == nil {
// Success, copy the downloaded file from the memory to the disk
print("Finished downloading!")
do {
try FileManager.default.copyItem(at: tempLocalUrl,to:
dirUrl.appendingPathComponent((response?.suggestedFilename)!))
if completion != nil {
completion!()
}
} catch (let writeError) {
print("Fliled to write file \(dirUrl) : \(writeError)")
}
} else {
print("Failure: \(String(describing: error?.localizedDescription))")
}
}
task.resume()
}
I want to write a unit test method to test whether it downloads the file from url
to the dirUrl
.
func testDownloadUrl(){
let fm = FileManager.default
let url = URL(string: "https://raw.githubusercontent.com/apple/swift/master/README.md")
fileDownloader.downloadUrl(url: url!, to: fm.temporaryDirectory, completion: nil)
// Check the contents of temp file
let tempContents = try? fm.contentsOfDirectory(atPath: fm.temporaryDirectory.path)
print("Contents: \(tempContents)")
}
However, there was no output "Finished downloading!" or "Failure ..." even though I passed the unit test, so I guess the completionHandler was not called in this test case.
My question is how to make the unit test method wait until the download task completes?
The standard idiom is to use Xcode asynchronous testing APIs, mostly the XCTestExpectation
class. Those are available since Xcode 6 so, if you are using a recent version, you should be covered ;)
The general async test template is as follows:
func testAsyncFunction() {
let asyncDone = expectation(description: "Async function")
...
someAsyncFunction(...) {
...
asyncDone.fulfill()
}
wait(for: [asyncDone], timeout: 10)
/* Test the results here */
}
This will block your test execution until the aforementioned function completes (or the specified timeout has elapsed).