Unit testing should be as fast as possible and anything that slows it down should be removed.

We have a more than 1K test cases in our application. As test cases got increased it slowed down running tests. I had a discussion about this with my colleagues and captured two words from discussion i.e. Set none to host application or use TestAppDelegate . I did research on host application and came to know that it is must to set for application tests. We have a tests in other target i.e. cocoa touch framework(library) that doesn’t need main application as host to run tests and it works perfectly there. Till now host application point is clear.

Testing Sequence goes like this:

Launch the simulator In the simulator, launch the app Inject the test bundle into the running app Run the tests

Whenever test case runs, it invokes main.m which invokes appDelegate heavy code. It’s good to use TestAppDelegate when test runs. It should be set up when we start new project to avoid any side effect as app delegate will grow over time. Unfortunately, we are going to use TestAppDelegate now.

Why use Test AppDelegate ?

When iOS launches an app, it needs one of the following things:

@UIApplicationMain notation: it’s applied to a class to indicate that it is the application delegate.

notation: it’s applied to a class to indicate that it is the application delegate. UIApplicationMain() function: it’s called in the main entry point—which is usually main.swift —to create the application object, the application delegate and set up the event cycle.

By default, an iOS project has a class AppDelegate with the notation @UIApplicationMain . It means that this class is the entry point of your app.

Then, iOS has to find the entry point for the UI. We can use two different ways to load the main UI component: either Using Storyboard or Load Programmatically .

Load programmatically:

Create A New App Entry Point (main.m)

First of all, we need a new entry point to load either the normal or the test AppDelegate depending on whether the app is launched by unit tests or not.

The entry point of an app can be either an AppDelegate with the notation @UIApplicationMain or the UIApplicationMain() function.

The first step is remove the @UIApplicationMain annotation from AppDelegate.swift, create a new file main.swift . In this file we have to check if the app is launched by unit tests:

let isRunningTests = NSClassFromString("XCTestCase") != nil

Now, we have to decide which app delegate class to load:

return isRunningTests ? NSStringFromClass(TestAppDelegate.self) : NSStringFromClass(AppDelegate.self)

Instead of TestAppDelegate nil can be also return.

return isRunningTests ? nil : NSStringFromClass(AppDelegate.self)

Final main.swift looks like this:

TestAppDelegate

We know that the TestAppDelegate is called just once and before the unit tests. It means that you have the possibility to run test logic in your TestAppDelegate once and before running the set of unit tests.

We don’t need to assign view controller to window here.

If you are using any ui test or snapshot framework which needs test to be hosted by an application with a key window then you need to use below test app delegate.

After this change all tests got passed in improved time.

If you use core data in app delegate and want to initialize there is a good article to follow: https://marcosantadev.com/fake-appdelegate-unit-testing-swift/