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

bhmjp9jg  于 12个月前  发布在  Swift
关注(0)|答案(3)|浏览(127)

我有一个OS X应用程序,它在启动时从服务器加载一些数据并将通知推送到NSUserNotificationCenter。现在我的问题是,这也发生在我的单元测试期间。我还没有找到任何方法来防止这种情况。当然,我可以stub HTTP加载。但在某些情况下,我想测试加载,然后无论如何都会发送通知。
我想做的是让测试运行不加载AppDelegate,而是加载一个我只用于测试的假的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/](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

rqenqsqc

rqenqsqc1#

这是我的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)
}

字符串
更紧凑一点!我使用Swift 4.1和XCode 9.4.1

iugsix8n

iugsix8n2#

经过几天的尝试和失败,我在苹果论坛上找到了答案:
问题是我的主.swift文件在初始化NSApplication之前初始化了我的AppDelegate。Apple文档清楚地表明,许多其他可可类在初始化时依赖于NSApplication启动和运行。显然,NSObject和NSDWindow就是其中的两个。
所以我在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类)。
我确信我将不得不调整这一点。特别是当一开始与用户界面测试。但目前它的工作。

weylhg0b

weylhg0b3#

我有同样的问题,当我运行测试用例.测试用例在AppDelegate崩溃.所以,我尝试了这个解决方案,工作得很好.我希望它会为你工作.
解决方案:-
步骤1:创建一个main.swift文件
步骤2:将这几行代码添加到main.swift文件中。

import UIKit

private func delegateClassName() -> String? {
    let className = NSClassFromString("XCTestCase") == nil ? NSStringFromClass(AppDelegate.self) : NSStringFromClass(TestingAppDelegate.self)
    return className
}

UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, delegateClassName())

字符串
步骤3:创建TestingAppDelegate.swift文件
步骤4:添加这一行代码

class TestingAppDelegate: UIResponder, UIApplicationDelegate {
}


步骤5:从AppDelegate.swift文件顶部删除@UIApplicationMain

现在运行您的测试用例。它将运行

相关问题