Fake AppDelegate for Unit Testing in Swift

Updated 29 July 2020

Save

The Fake AppDelegate works the same as our default AppDelegates do but in a different manner. Unit tests are an important part of software development and they must be fast and without side effects. Unfortunately, if you don’t pay attention, in iOS development you may risk side effects every time you run unit tests for your application. For this reason, a fake AppDelegate is a good way to enhance your tests.

Why Fake AppDelegate?

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

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 Main Interface or Load Programmatically.

Using Main Interface

By default, an iOS project has a storyboard Main.storyboard where we have the main UIViewController of our app. By default, iOS searches the UI entry point inside this storyboard since it’s set in the Info.plist:

By default the initial view controller of this storyboard is ViewController, which becomes our main UI component.

With this approach, we often load the data of our application inside this view controller to use in the whole app:

Load Programmatically

On the other hand, we can load the main UI component programmatically in the AppDelegate:

In this example, we create a new UIViewController and assign it to the rootViewController of the main window. In this way the new view controller will become the main UI component of our application.

When we use this approach, we often load the data in the AppDelegate and inject it inside the view controller:

It’s the same process that occurs when you launch the app to debug it. There are no differences. This means that, when you run the unit tests, the AppDelegate and main UI components are loaded as usual to run the app. If you check the example used above, you can notice that the AppDelegate and the main UI component have the fetch of persons as business logic.

At this point, you may be thinking that it’s not a big problem. It can be a problem if at the startup of your application you read/write in a database, send API requests to insert/edit entities, or compute-heavy computations which may be time-consuming, slowing down the tests. For this reason, we need a way to skip these behaviors when you run unit tests to avoid side effects. A solution is a fake AppDelegate.

Fake AppDelegate

Before starting, if you are loading the main interface from Info.plist—like I have shown previously—you have to remove it and load the main storyboard programmatically:

  1. Remove the storyboard from the plist:
  2. Load the storyboard programmatically:

Now we are ready to start to create a fake AppDelegate.

Create A New App Entry Point

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

As said at the beginning of this article, the entry point of an app can be either an AppDelegate with the notation @UIApplicationMain or the UIApplicationMain() function. Now, we need the later.

The first step is creating a new file main.swift, In this file, we have to check if the app is launched by unit tests:

Then, we have to decide which AppDelegate class to load. For the class to use when the app is launched by unit tests, we have two choices: we can use either a FakeAppDelegate class where we can add the test logic to run before the tests—I’ll explain it better in “Create FakeAppDelegate”:

Or you can merely return nil. In this way, when you run the tests you don’t load any AppDelegate class. It would be the fastest and recommended solution if you don’t have to add behaviours in the FakeAppDelegate:

If you decide to use the nil value you can skip the section “Create FakeAppDelegate”.

Finally, we must set the arguments used to launch our application:

The final main.swift file will be like this:

FakeAppDelegate

Without AppDelegate

Create FakeAppDelegate

Here we are, you have just created the file main.swift and you decided that you want a FakeAppDelegate class. The point is, why do we want a FakeAppDelegate?

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

Let’s look at an example:

Suppose that we want to write in a file every time we run the unit tests. We can start creating a new class called FakeAppDelegate.swift, and in its constructor, we call the method to write the log message in a file:

Remember to extend NSObject otherwise the function UIApplicationMain in main.swift won’t be able to instantiate the class FakeAppDelegate.

You can find more details here.

Thank You!!

author
. . .

Leave a Comment

Your email address will not be published. Required fields are marked*


Be the first to comment.

Start a Project


    Message Sent!

    If you have more details or questions, you can reply to the received confirmation email.

    Back to Home