如何使用 `completionHandler` 为`downloadTask` 编写单元测试?

Posted

技术标签:

【中文标题】如何使用 `completionHandler` 为`downloadTask` 编写单元测试?【英文标题】:How to write unit test for `downloadTask` with `completionHandler `? 【发布时间】:2017-11-05 20:00:41 【问题描述】:

这是我的下载功能:

// 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()

我想写一个单元测试方法来测试它是否将文件从url下载到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)")
    

但是,没有输出“下载完成!”或者“失败...”,即使我通过了单元测试,所以我猜在这个测试用例中没有调用completionHandler。

我的问题是如何让单元测试方法等到下载任务完成?

【问题讨论】:

【参考方案1】:

标准习惯用法是使用Xcode asynchronous testing APIs,主要是XCTestExpectation 类。这些从 Xcode 6 开始就可用,因此,如果您使用的是最新版本,则应该包括在内;)

一般的异步测试模板如下:

func testAsyncFunction() 
    let asyncDone = expectation(description: "Async function")
    ...
    someAsyncFunction(...) 
        ...
        asyncDone.fulfill()
    
    wait(for: [asyncDone], timeout: 10)
    /* Test the results here */

这将阻止您的测试执行,直到上述功能完成(指定的超时已经过去)。

【讨论】:

以上是关于如何使用 `completionHandler` 为`downloadTask` 编写单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Swifts DispatchQueue() 和 completionHandlers 组织网络登录?

如何保存 CompletionHandler 返回的值?

作为命令行工具运行时,如何让 NSURLSession 处理 completionHandler

UIActivityViewController completionHandler 如何检查活动是不是发送成功?

返回方法中的 sendAsynchronousRequest 和 completionHandler

在 Alamofire Swift 2.2 中使用 completionHandler