Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: How to not load AppDelegate during Tests

Tags:

macos

swift

cocoa

I have an OS X application which on startup loads some data from a server and pushes notifications to the NSUserNotificationCenter. Now I have the problem that this also happens during my unit tests. I found no way yet to prevent this. Of course I could stub the HTTP loads. But in some cases I want to test the loading and then the notifications get sent anyway.

What I'm trying to do is to make the test runs not load the AppDelegate but a fake one that I'm only using for tests. I found several examples [1] on how to do that with UIApplicationMain, where you can pass a specific AppDelegate class name. The same is not possible with NSApplicationMain [2].

What I've tried is the following:

Removed @NSApplicationMain from AppDelegate.swift, then added a main.swift with the following content:

class FakeAppDelegate: NSObject, NSApplicationDelegate {
}

NSApplication.sharedApplication()
NSApp.delegate = FakeAppDelegate()
NSApplicationMain(Process.argc, Process.unsafeArgv)

This code runs before tests but has no effect at all.

I might have to say: My AppDelegate is almost empty. To handle the MainMenu.xib stuff I made a separate view controller which does the actual loading and notification stuff in awakeFromNib.

[1] http://www.mokacoding.com/blog/prevent-unit-tests-from-loading-app-delegate-in-swift/

[2] https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Miscellaneous/AppKit_Functions/#//apple_ref/c/func/NSApplicationMain

like image 741
Phil Avatar asked Aug 24 '16 06:08

Phil


People also ask

What is the difference between AppDelegate and SceneDelegate?

AppDelegate is responsible for handling application-level events, like app launch and the SceneDelegate is responsible for scene lifecycle events like scene creation, destruction and state restoration of a UISceneSession.

What is @main in AppDelegate?

UIApplicationMain first instantiates UIApplication and retains its instance to serve as the shared application instance ( UIApplication. shared ) and then instantiates the app delegate marked @Main as the application instance's delegate. The main method exists as a type method.

What does AppDelegate swift do?

The app delegate is effectively the root object of your app, and it works in conjunction with UIApplication to manage some interactions with the system. Like the UIApplication object, UIKit creates your app delegate object early in your app's launch cycle so it's always present.

What is XCTest Swift?

Use the XCTest framework to write unit tests for your Xcode projects that integrate seamlessly with Xcode's testing workflow. Tests assert that certain conditions are satisfied during code execution, and record test failures (with optional messages) if those conditions aren't satisfied.


1 Answers

Just an update on the previous accept answer, this is my main.swift:

private func isTestRun() -> Bool {
    return NSClassFromString("XCTestCase") != nil
}

if isTestRun() {
    // This skips setting up the app delegate
    NSApplication.shared.run()
} else {
    // For some magical reason, the AppDelegate is setup when
    // initialized this way
    _ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
}

A bit more compact! I'm using Swift 4.1 and XCode 9.4.1

like image 108
Orgmir Avatar answered Sep 29 '22 09:09

Orgmir