Swift:如何在测试期间不加载AppDelegate

我有一个OS X应用程序,它在启动时从服务器加载一些数据并将通知推送到NSUserNotificationCenter.

现在我遇到的问题是在单元测试期间也会发生这种情况.我发现还没有办法阻止这一点.当然我可以存根HTTP负载.但在某些情况下,我想测试加载,然后无论如何都会发送通知.

我想要做的是让测试运行不加载AppDelegate,而是一个假的,我只用于测试.我找到了几个关于如何使用UIApplicationMain执行此操作的示例[1],您可以在其中传递特定的AppDelegate类名称. NSApplicationMain [2]无法做到这一点.

我试过的是以下内容:

从AppDelegate.swift中删除了@NSApplicationMain,然后添加了一个main.swift,其中包含以下内容:

class FakeAppDelegate: NSObject, NSApplicationDelegate {
}

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

此代码在测试之前运行,但完全没有效果.

我可能不得不说:我的AppDelegate几乎是空的.为了处理MainMenu.xib的东西,我创建了一个单独的视图控制器,它在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

最佳答案 经过几天的尝试和失败后,我在
Apple forums找到了答案:

The problem was that my main.swift file was initializing my AppDelegate before NSApplication had been initialized. The Apple documentation makes it clear that lots of other Cocoa classes rely on NSApplication to be up and running when they are initialized. Apparently, NSObject and NSWindow are two of them.

所以我在main.swift中的最终和工作代码如下所示:

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

private func runApplication(
    application: NSApplication = NSApplication.sharedApplication(),
    delegate: NSObject.Type?   = nil,
    bundle: NSBundle?          = nil,
    nibName: String            = "MainMenu") {

    var topLevelObjects: NSArray?

    // Actual initialization of the delegate is deferred until here:
    application.delegate = delegate?.init() as? NSApplicationDelegate

    guard bundle != nil else {
        application.run()
        return
    }

    if bundle!.loadNibNamed(nibName, owner: application, topLevelObjects: &topLevelObjects ) {
        application.run()
    } else {
        print("An error was encountered while starting the application.")
    }
}

if isTestRun() {
    let mockDelegateClass = NSClassFromString("MockAppDelegate") as? NSObject.Type
    runApplication(delegate: mockDelegateClass)
} else {
    runApplication(delegate: AppDelegate.self, bundle: NSBundle.mainBundle())
}

所以之前的实际问题是Nib在测试期间被加载.此解决方案可防止这它只是在检测到测试运行时通过模拟应用程序委托加载应用程序(通过查找XCTest类).

我相信我不得不再调整一下.特别是在开始使用UI测试时.但目前它的工作原理.

点赞