Start with a Fresh Test Spy

If you didn’t work through Chapter 12, Testing Network Requests (with Mocks), the full-fledged mock object we developed would be a confusing starting point for learning closure techniques. To simplify this example, let’s set that MockURLSession aside and start over with a fresh test spy. (If you’re continuing with last chapter’s code, when you see NetworkResponse or NetworkResponseTests below, mentally convert to NetworkRequest and NetworkRequestTests.)

Select the NetworkResponseTests group in the Project Navigator and press -N to make a new file. Click the iOS selector at the top, select Swift File, and press Next. In the dialog, enter SpyURLSession.swift as the name of the file. In the Save dialog, double-check that the test target is selected, not the app target. Press Create and enter the following code:

NetworkResponse/NetworkResponseTests/SpyURLSession.swift
 @testable​ ​import​ ​NetworkResponse
 import​ ​Foundation
 
 private​ ​class​ ​DummyURLSessionDataTask​: ​URLSessionDataTask​ {
 override​ ​func​ ​resume​() {
  }
 }
 
 class​ ​SpyURLSession​: ​URLSessionProtocol​ {
 }

Xcode will show a Swift error:

 Type 'SpyURLSession' does not conform to protocol 'URLSessionProtocol'

In the Xcode menu, select Editor Fix All Issues. Xcode will generate a stub for the protocol method. Fill in the rest as shown here to increment the call count, capture the arguments, and return a DummyURLSessionDataTask:

NetworkResponse/NetworkResponseTests/SpyURLSession.swift
 var​ dataTaskCallCount = 0
 var​ dataTaskArgsRequest: [​URLRequest​] = []
»var​ dataTaskArgsCompletionHandler:
» [(​Data​?, ​URLResponse​?, ​Error​?) -> ​Void​] = []
 
 func​ ​dataTask​(
  with request: ​URLRequest​,
  completionHandler: ​@escaping​ (​Data​?, ​URLResponse​?, ​Error​?) -> ​Void
 ) -> ​URLSessionDataTask​ {
  dataTaskCallCount += 1
  dataTaskArgsRequest.​append​(request)
» dataTaskArgsCompletionHandler.​append​(completionHandler)
 return​ ​DummyURLSessionDataTask​()
 }

This is identical to Make a Test Spy except that now we’re capturing the completionHandler argument.