Swift:如何在测试期间不加载 AppDelegate
Posted
技术标签:
【中文标题】Swift:如何在测试期间不加载 AppDelegate【英文标题】:Swift: How to not load AppDelegate during Tests 【发布时间】:2016-08-24 06:52:58 【问题描述】:我有一个 OS X 应用程序,它在启动时从服务器加载一些数据并将通知推送到NSUserNotificationCenter
。
现在我有一个问题,在我的单元测试期间也会发生这种情况。我发现没有办法阻止这种情况。当然,我可以存根 HTTP 负载。但在某些情况下,我想测试加载,然后无论如何都会发送通知。
我想要做的是让测试运行不加载AppDelegate
,而是一个我只用于测试的假的。我找到了几个示例 [1],说明如何使用 UIApplicationMain
执行此操作,您可以在其中传递特定的 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
【问题讨论】:
【参考方案1】:只是对之前接受答案的更新,这是我的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
【讨论】:
【参考方案2】:经过几天的尝试和失败,我在 Apple forums 上找到了答案:
问题是我的 main.swift 文件在 NSApplication 初始化之前初始化了我的 AppDelegate。 Apple 文档清楚地表明,许多其他 Cocoa 类在初始化时都依赖 NSApplication 来启动和运行。显然,NSObject 和 NSWindow 是其中的两个。
所以我在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 测试开始时。但目前它有效。
【讨论】:
我收到Cannot convert value of type 'AppDelegate.Type' to expected argument type 'NSApplication'
以上是关于Swift:如何在测试期间不加载 AppDelegate的主要内容,如果未能解决你的问题,请参考以下文章