How do I set up unit tests and mocks with URLSession in Swift?

Unit testing in Swift can be quite straightforward, especially when working with URLSession. To effectively test code that relies on network requests, you'll want to create a mock URLSession. This allows you to simulate network responses without making actual HTTP requests. Below, you will find an example of how to set up unit tests and mocks with URLSession in Swift.

import XCTest import Foundation // Define a protocol for URLSession to allow mocking protocol URLSessionProtocol { func dataTask(with url: URL, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask } extension URLSession: URLSessionProtocol { func dataTask(with url: URL, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask { return dataTask(with: url, completionHandler: completionHandler) } } // Create a mock URLSession for testing class MockURLSession: URLSessionProtocol { var mockedData: Data? var mockedError: Error? func dataTask(with url: URL, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask { completionHandler(mockedData, nil, mockedError) return URLSessionDataTask() // Return a dummy task } } // Example network manager using URLSession class NetworkManager { var session: URLSessionProtocol init(session: URLSessionProtocol = URLSession.shared) { self.session = session } func fetchData(from url: URL, completion: @escaping (Data?, Error?) -> Void) { session.dataTask(with: url) { data, response, error in completion(data, error) }.resume() } } // Unit tests class NetworkManagerTests: XCTestCase { var networkManager: NetworkManager! var mockSession: MockURLSession! override func setUp() { super.setUp() mockSession = MockURLSession() networkManager = NetworkManager(session: mockSession) } func testFetchData_Success() { let expectedData = "Test data".data(using: .utf8) mockSession.mockedData = expectedData let expectation = self.expectation(description: "Completion Handler Called") networkManager.fetchData(from: URL(string: "http://test.com")!) { data, error in XCTAssertNil(error) XCTAssertEqual(data, expectedData) expectation.fulfill() } waitForExpectations(timeout: 1, handler: nil) } func testFetchData_Error() { let expectedError = NSError(domain: "", code: 1, userInfo: nil) mockSession.mockedError = expectedError let expectation = self.expectation(description: "Completion Handler Called") networkManager.fetchData(from: URL(string: "http://test.com")!) { data, error in XCTAssertNotNil(error) XCTAssertEqual((error as NSError?)?.code, 1) expectation.fulfill() } waitForExpectations(timeout: 1, handler: nil) } }

Unit Testing Swift URLSession Mocking XCTest Networking Functional Testing