Categories
Generics iOS Swift UIKit

Testing networking code with custom URLProtocol on iOS

Testing networking code might sound tricky at first but in reality, it just means using custom URLProtocol what returns data we would like to. This allows testing the networking module without mocking URLSession. Using this approach we could do so much more, even integrating a third party networking library.

Networking class wrapping URLSession

Firstly, let’s set up a simple WebClient class what uses URLSession for initiating networking requests. It has a fetch method for loading URLRequest and transforming the response to expected payload type using Codable. As payload can be any type, we use generics here. Note that we need to pass in the payload type as a variable because we need the exact type when decoding the JSON data. How can we test this as URLSession would try to send an actual request to designated URL? As unit tests should behave exactly the same all the time and should not depend on external factors, then using a separate test server is not preferred. Instead, we can intercept the request and provide the response with custom URLProtocol.

final class WebClient {
private let urlSession: URLSession
init(urlSession: URLSession) {
self.urlSession = urlSession
}
func fetch<T: Decodable>(_ request: URLRequest, requestDataType: T.Type, completionHandler: @escaping (Result<T, FetchError>) -> Void) {
let dataTask = urlSession.dataTask(with: request) { (data, urlResponse, error) in
if let error = error {
DispatchQueue.main.async {
completionHandler(.failure(.connection(error)))
}
return
}
guard let urlResponse = urlResponse as? HTTPURLResponse else {
DispatchQueue.main.async {
completionHandler(.failure(.unknown))
}
return
}
switch urlResponse.statusCode {
case 200..<300:
do {
let payload = try JSONDecoder().decode(requestDataType, from: data ?? Data())
DispatchQueue.main.async {
completionHandler(.success(payload))
}
}
catch let jsonError {
DispatchQueue.main.async {
completionHandler(.failure(.invalidData(jsonError)))
}
}
default:
DispatchQueue.main.async {
completionHandler(.failure(.response(urlResponse.statusCode)))
}
}
}
dataTask.resume()
}
}
extension WebClient {
enum FetchError: Error {
case response(Int)
case invalidData(Error)
case connection(Error)
case unknown
}
}
view raw WebClient.swift hosted with ❤ by GitHub

Creating custom URLProtocol for unit tests

URLProtocol is meant to be overridden. Firstly, we’ll need to override canInit(with:) and return true here allowing URLSession to use this protocol for any URL request. Secondly, it is required to override canonicalRequest(for:) where we can just return the same request. Thirdly, startLoading, where we have the loading logic which uses class property for returning appropriate response. This allows us to set this property in unit tests and then returning the result when URLSession handles the fetch request. Finally, URLProtocol also needs to define stopLoading method what we can just leave empty as this protocol is not asynchronous.

final class TestURLProtocol: URLProtocol {
override class func canInit(with request: URLRequest) -> Bool {
return true
}
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
return request
}
static var loadingHandler: ((URLRequest) -> (HTTPURLResponse, Data?, Error?))?
override func startLoading() {
guard let handler = TestURLProtocol.loadingHandler else {
XCTFail("Loading handler is not set.")
return
}
let (response, data, error) = handler(request)
if let data = data {
client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
client?.urlProtocol(self, didLoad: data)
client?.urlProtocolDidFinishLoading(self)
}
else {
client?.urlProtocol(self, didFailWithError: error!)
}
}
override func stopLoading() {}
}

Using TestURLProtocol for mocking network requests in unit tests

Setting up a unit test requires to set the TestURLProtocol’s loadingHandler and returning the data we would like to. Then we create URLSessionConfiguration and set our TestURLProtocol to protocolClasses. After that we can use this configuration for initialising URLSession and using this session in our WebClient which handles fetch requests. That is pretty much all we need to do for testing networking requests.

final class WebClientTests: XCTestCase {
override func tearDown() {
TestURLProtocol.loadingHandler = nil
}
struct TestPayload: Codable, Equatable {
let country: String
}
func testFetchingDataSuccessfully() {
let expected = TestPayload(country: "Estonia")
let request = URLRequest(url: URL(string: "https://www.example.com")!)
let responseJSONData = try! JSONEncoder().encode(expected)
TestURLProtocol.loadingHandler = { request in
let response = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)!
return (response, responseJSONData, nil)
}
let expectation = XCTestExpectation(description: "Loading")
let configuration = URLSessionConfiguration.ephemeral
configuration.protocolClasses = [TestURLProtocol.self]
let client = WebClient(urlSession: URLSession(configuration: configuration))
client.fetch(request, requestDataType: TestPayload.self) { (result) in
switch result {
case .failure(let error):
XCTFail("Request was not successful: \(error.localizedDescription)")
case .success(let payload):
XCTAssertEqual(payload, expected)
}
expectation.fulfill()
}
wait(for: [expectation], timeout: 1)
}
}

Summary

Testing networking code at first might sound daunting. But actually it just boils down to using custom URLProtocol and providing response we need to in our test.

If this was helpful, please let me know on Mastodon@toomasvahter or Twitter @toomasvahter. Feel free to subscribe to RSS feed. Thank you for reading.

Example project

TestingNetworkRequests (Xcode 5.0, Xcode 10.2.1)

Resources

Categories
Generics iOS Swift UIKit

Instantiating view controllers from UIStoryboard on iOS

There are several ways how to create user interfaces on iOS: programmatically, xib per view or using storyboard for multiple views. Personally I tend to use xibs and programmatically created layouts more but sometimes I also use UIStoryboard – depends on the situation on hand. Therefore I like to present two small additions to UIStoryboard API what makes instantiating view controllers more compact and convenient to use.

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "contacts") as! ContactsViewController

The approach I would like to present is a generic instantiate view controller method. It implies that in storyboard, the view controller’s identifier is set to the name of the view controller class.

When Storyboard ID for the view controller is set to the class name, it is now easy to derive the identifier from a type. It should be noted that in Swift, NSStringFromClass returns string with format <module name>.<class name>. Therefore it required to parse the returned string and taking only the class name part.

extension UIStoryboard {
func instantiateViewController<T: UIViewController>(withType type: T.Type) -> T {
let className = NSStringFromClass(type).split(separator: ".").last!
return instantiateViewController(withIdentifier: String(className)) as! T
}
}

In addition, with convenience method for getting storyboard, we can get to end result which is more compact and also avoids having identifier strings in the code.

extension UIStoryboard {
class var main: UIStoryboard {
return UIStoryboard(name: "Main", bundle: nil)
}
}
let viewController = UIStoryboard.main.instantiateViewController(withType: ContactsViewController.self)

If this was helpful, please let me know on Mastodon@toomasvahter or Twitter @toomasvahter. Feel free to subscribe to RSS feed. Thank you for reading.

Categories
Generics Swift

Singly linked list with generics in Swift

In this post we will go over basic usage of generics in Swift by building a simple singly linked list.

Introduction to generics

Generic code is code where the functionality is described without using specific types. Meaning, the code can use any types what match with constraints (if there are any). It’s best to take a look on an example. See how separate functions can be replaced with a single implementation.

// non-generic functions
func someFunctionInt(_ values: [Int]) {}
func someFunctionString(_ values: [String]) {}
// generic
func someFunction<T>(_ values: [T]) {}
// non-generic functions
someFunctionInt([1, 2, 3])
someFunctionString(["a", "b", "c"])
// generic
someFunction([1, 2, 3])
someFunction(["a", "b", "c"])
// Type constraint
func someSortFunction<T: Comparable>(_ values: [T]) -> [T] {
return values.sorted()
}
let sorted = someSortFunction([3, 7, 5, 1])
print(sorted) // [1, 3, 5, 7]

Generic implementation defines a placeholder for a type (in angle brackets), in those examples T was used (can be something else but it is the most common placeholder). If multiple type placeholders are needed, placeholders are separated with commas. In addition, it is possible to constrain the type, for example, requiring the type to conform to comparable protocol allowing to use comparisons in the generic function’s implementation. It’s the bare minimal knowledge required for getting started with generics. There is a lot more about it.

Singly linked list

Singly linked list is a data structure where every node knows about the next node, but not about the preceding node. The benefit of such data structure is efficiency when inserting and removing nodes. On the other hand it does not allow random access of nodes.
Defining a generic linked list is quite easy. First we need a LinkedList struct storing the first node. Node stores a value and the next node. When inserting or removing nodes from the list, next property is updated. Therefore node needs to have reference semantics for making sure all the objects are pointing at the correct next object (in value semantics new instances would be created when mutating the next property and it would break the continuity of the list).

struct LinkedList<T> {
final class Node<T> {
let value: T
init(_ value: T, next: Node<T>? = nil) {
self.value = value
self.next = next
}
var next: Node<T>? = nil
}
var first: Node<T>? = nil
}

As said before, inserting and removing nodes is just a matter of updating the next properties. Therefore when inserting a node, its next node is the current node’s next node and the current node’s next node is the inserted node.

extension LinkedList {
@discardableResult func insert<T>(_ node: Node<T>, after: Node<T>) -> Node<T> {
node.next = after.next
after.next = node
return node
}
@discardableResult mutating func prepend(_ node: Node<T>) -> Node<T> {
node.next = first
self.first = node
return node
}
@discardableResult func remove(after node: LinkedList<T>.Node<T>) -> LinkedList<T>.Node<T>? {
let removed = node.next
node.next = node.next?.next
return removed
}
}

And finally, using generic linked list.

print("Populating parking lot.")
var parkingLot = LinkedList<String>()
parkingLot.prepend(LinkedList.Node("Car"))
let truck = parkingLot.prepend(LinkedList.Node("Truck"))
parkingLot.insert(LinkedList.Node("Chopper"), after: truck)
parkingLot.forEach(body: { print($0.value) })
print("Empty: \(parkingLot.isEmpty)")
/*
Populating parking lot.
Truck
Chopper
Car
Empty: false
*/
print("Rearranging parking lot.")
parkingLot.remove(after: truck)
parkingLot.forEach(body: { print($0.value) })
/*
Rearranging parking lot.
Truck
Car
*/
print("Populating numbers.")
var numbers = LinkedList<Int>()
let first = numbers.prepend(LinkedList.Node(1))
numbers.insert(LinkedList.Node(2), after: first)
numbers.forEach(body: { print($0.value) })
/*
Populating numbers.
1
2
*/

Summary

In this post we took a quick look at how to write generic code and applied that knowledge on generic version of singly linked list. It should be noted that here we used only the basics of generics and for example the linked list implementation could also benefit from associated types allowing to replace Node with for example, Element.

Playground

SinglyLinkedList (GitHub)

References

Generics in Swift (Apple)
Linked lists (Wikipedia)

Categories
Generics iOS

Making a property observable from outer scope using generic class Observable

We will look into how to make a property observable using a separate class managing the observers. It is an alternative and simple way of observing property changes without using ReactiveSwift, Key-Value Observing or anything else similar. It can be an excellent glue between Model and View Model in MVVM or between View and Presenter when using VIPER architecture.

Creating a class Observable

final class Observable<T> {
init(_ value: T) {
self.value = value
}
var value: T {
didSet {
changeHandlers.forEach({ $0.handler(value) })
}
}
typealias ChangeHandler = ((T) -> Void)
private var changeHandlers: [(identifier: Int, handler: ChangeHandler)] = []
/**
Adds observer to the value.
- parameter initial: The handler is run immediately with initial value.
- parameter handler: The handler to execute when value changes.
- returns: Identifier of the observer.
*/
@discardableResult func observe(initial: Bool = false, handler: @escaping ChangeHandler) -> Int {
let identifier = UUID().uuidString.hashValue
changeHandlers.append((identifier, handler))
guard initial else { return identifier }
handler(value)
return identifier
}
/**
Removes observer to the value.
- parameter observer: The observer to remove.
*/
func removeObserver(_ observer: Int) {
changeHandlers = changeHandlers.filter({ $0.identifier != observer })
}
}

The class Observable holds a value what can be of any type. Now when the value is store by the class itself we can use Swift’s property observer and then calling change handlers. This allows creating an object with observable properties and observing those properties from other objects. Moreover, it is possible to remove any of the added observers.
Let’s take a look on an example of class “Pantry” what has a property holding array of jams. In the example we will add two observers: one reacting to changes and the other one what will also react to the initial value. When one of the observer is removed and the array of jams changes, only one of the observers is triggered.

final class Pantry {
let jams = Observable([Jam(flavour: .apple)])
func add(jam: Jam) {
jams.value.append(jam)
}
}
struct Jam {
enum Flavour: String {
case apple, orange
}
let flavour: Flavour
init(flavour: Flavour) {
self.flavour = flavour
}
}
let pantry = Pantry()
print("Adding count and contents observers.")
let observer = pantry.jams.observe { (jams) in
print("Pantry now has \(jams.count) jars of jam.")
}
pantry.jams.observe(initial: true) { (jams) in
let contents = jams.map({ $0.flavour.rawValue }).joined(separator: ", ")
print("Jams in pantry: \(contents)")
}
print("Adding jam to pantry.")
pantry.add(jam: Jam(flavour: .orange))
print("Removing count observer.")
pantry.jams.removeObserver(observer)
print("Adding jam to pantry.")
pantry.add(jam: Jam(flavour: .apple))
/*
Adding count and contents observers.
Jams in pantry: apple
Adding jam to pantry.
Pantry now has 2 jars of jam.
Jams in pantry: apple, orange
Removing count observer.
Adding jam to pantry.
Jams in pantry: apple, orange, apple
*/

Today we learned how to very easily make a property observable from outer scope of the object owning the property.
Thank you for reading.

Download ObservableProperty playground.