Setting things up

If your app doesn’t already have a UI testing target, you will have to add one by going to File > New > Target > iOS UI Testing Bundle .

How XCTest framework works

The first thing that trips most people is that you cannot stub your API calls in your XCTestCase , because it just opens your app so any stubbing you do there will be lost.

You have to use launch arguments instead and let your app knows that it is in UI test mode and what API calls need stubbing.

How to stub your API calls

When it comes to returning fake data (predetriment responses) to your app you have a bunch of options like mocking repositories (managers, etc.. based on your app architecture) protocols that should make API calls. In other words circumventing the call before it actually hit the network layer.

Another option is stubbing all the web calls that your app might make during a test. And with OHHTTPStubs your app actually execute all the code in your repository and when you hit the network layer OHHTTPStubs returns a predetriment response or an error. Unlike the first option this can actually expose hidden errors in your repository.

An easy structure to stub existing and future API calls

In my previous attempts to write maintainable UI tests mostly on Android, mocking repository methods has always been tricky specially from the tester point of view because they do not get to work on the codebase on daily basis. On the other hand you can easily run the app and find out all the requests going out of the app and their responses and easily stub them without having to worry about what is going on in the code.

I still wanted to make the code clear and somewhat easily mappable to our API structure/documentations. Any REST backend has different APIs and each API has a bunch of endpoints so that is exactly how the code looks like. I might even look at auto-generating all this code in the future.

protocol StubApi {

} protocol StubEndpoint {



var path: String { get }

var name: String { get }

var type: String { get }

var method: HttpMethod { get }

var params: [String: String]? { get }



} extension StubEndpoint {



// Helper serialization function.

func toDictionary() -> [String: String] {

var dictionary = [String: String]()

dictionary["path"] = path

dictionary["name"] = name

dictionary["type"] = type

dictionary["method"] = method.rawValue



if let params = params {

let json = try! JSONSerialization.data(withJSONObject: params, options: JSONSerialization.WritingOptions())

dictionary["params"] = String(data: json, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))

}



return dictionary

}



}

I also included the HTTP methods and resource types that the StubbingManager would support.

enum HttpMethod: String {

case GET, POST, DELETE, PUT



static func fromString(rawValue: String?) -> HttpMethod {

guard let rawValue = rawValue else { fatalError() }



switch rawValue {

case HttpMethod.GET.rawValue:

return .GET

case HttpMethod.POST.rawValue:

return .POST

case HttpMethod.DELETE.rawValue:

return .DELETE

case HttpMethod.PUT.rawValue:

return .PUT

default:

fatalError()

}

}

} enum ResourceType: String {

case JSON

}

An example API stub would look something like