How to get URLProtocol instance from URLSession

I'm trying to create a network request mocking infrastructure for my iOS app. I'm using a mock URLProtocol to do this. My challenge is that I want to load custom data for each URLSession. In my setupWithError() in my unit tests, I basically do:

        let config = URLSessionConfiguration.ephemeral

        config.protocolClasses = [URLProtocolMock.self]

        let session = URLSession(configuration: config)

        APIManager.shared.session = session

        <session.URLProtocolMock>.loadJSMocks(filename: "AddItemUITest.js")

All of the examples I see for doing mocks this way, create static variables in the URLProtocolMock to allow configuring data. I'd like to be able to run tests in parallel, so static variables won't work.

I couldn't find an obvious way to get the protocol instance from the URLSession. Is there a non-obvious way? ;-)

Thanks!

Greg

P.S. And in the course of writing this, I realized that I have another problem with static APIManager session sharing. But that one I know how to solve :-)

I generally recommend that you not try to mock URLSession in this way. The problem here is that there’s a lot of glue code between the modern API provided by URLSession and the ancient API supported by URLProtocol. Indeed, this is something I touch on in the Caveats section of the read me for the CustomHTTPProtocol sample code. And that was 8 years ago; things have only got worse since then.

So, when you go down this path you end up spending more time testing your URLProtocol implementation, and the system’s glue between URLSession and that code, than you do testing your own code.

A better approach is to build your networking code on top of your own abstraction layer — one that’s focused on your specific requirements and doesn’t include the full complexity of URLSession — and then mock that.


I couldn't find an obvious way to get the protocol instance from the URLSession.

This question doesn’t make sense. The system creates a new instance of the protocol for each request.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

So global variable it is (it's good to know that a new protocol instance is created for each request, that wasn't obvious). The problem with mocking on top of the URLProtocol code is you're even farther from testing your code's behavior in the system. At least with URLProtocol mocking I'm testing down to that layer of the system. This also works then for Previews and unit tests as well as the UI tests. Mocks won't help with those cases. But thanks for taking the time to answer!

How to get URLProtocol instance from URLSession
 
 
Q