【问题标题】:Can you do test setup before application loads in Swift?您可以在 Swift 中加载应用程序之前进行测试设置吗?
【发布时间】:2020-05-24 03:24:26
【问题描述】:

我是一名 Swift/MacOS 新手,正在开发 MacOS 应用程序,我在主 ViewController 的 viewDidLoad() 方法中进行了一些涉及钥匙串访问和 API 调用的设置。

我正在为我的模型进行单元测试,所以我不需要并且实际上不希望 viewDidLoad() 中的代码运行。但是,据我所知,应用程序已加载并且这些方法在测试用例 setup() 方法之前运行,所以我不知道如何进行任何模拟或其他操作。

我正在使用 Xcode 11.5 和 Swift 5。

【问题讨论】:

  • 嗯,对我来说显而易见的答案是不要从视图控制器执行任何 API 调用,而是从您从视图控制器调用的特定服务类执行任何 API 调用。如果您在视图控制器中使用依赖注入,那么模拟服务类和测试视图控制器会容易得多。
  • 单元测试将启动您设置为“NSApplicationMain”的代码,因此它将自动设置窗口和视图控制器。您可以添加代码来手动设置,而不是使用注释,然后您将使用不同的 NSApplicationMain 类作为入口点。
  • @JoakimDanielson API 调用已经在服务类中,但是视图控制器在测试用例设置之前加载,所以我不明白我有机会在哪里注入依赖项。我不是(在这种情况下)测试视图控制器,它只是自动加载。

标签: swift xcode macos unit-testing


【解决方案1】:

一种方法是在运行单元测试时使用单独的NSApplicationMain,而在“正常”运行时使用单独的NSApplicationMain

首先从您当前的AppDelegate 类中删除@NSApplicationMain 注释。它最终应该看起来像这样:

AppDelegate.swift

import AppKit

class AppDelegate: NSObject, NSApplicationDelegate {
  func applicationDidFinishLaunching(_ aNotification: Notification) {
    print("Debug/Production run")

    // Insert code here to initialize your application
  }

  func applicationWillTerminate(_ aNotification: Notification) {
    // Insert code here to tear down your application
  }
}

现在创建一个名为 AppDelegateUnitTesting.swift 的新文件,其源代码应如下所示:

AppDelegateUnitTesting.swift

import Foundation
import Cocoa

class AppDelegateTesting: NSObject, NSApplicationDelegate {
  func applicationDidFinishLaunching(_ aNotification: Notification) {
    print("Unit Testing Run")
    // Insert code here to initialize your application
  }

  func applicationWillTerminate(_ aNotification: Notification) {
    // Insert code here to tear down your application
  }
}

现在添加一个名为main.swift 的新文件,该文件将确定我们的应用在哪个环境中运行,源代码应该是这样的:

ma​​in.swift

import Foundation
import Cocoa

let isRunningTests = NSClassFromString("XCTestCase") != nil &&
  ProcessInfo.processInfo.arguments.contains("-XCUnitTests")

fileprivate var delegate: NSApplicationDelegate?

if !isRunningTests {
  delegate = AppDelegate()
  NSApplication.shared.delegate = delegate

  // See this Answer to initialize the Windows programmatically
  // https://stackoverflow.com/a/44604229/496351
} else {
  delegate = AppDelegateTesting()
  NSApplication.shared.delegate = delegate

}
NSApplication.shared.run()

要确定它是否在单元测试环境中运行,它会检查它是否可以加载 XCTestClass(仅在测试时注入)并检查是否存在 -XCUnitTest 命令行参数,我们必须设置这个参数我们自己作为 Scheme 的 Test 操作的一部分,如下图所示

完成所有这些操作后,您应该会在按下播放按钮时看到打印的消息 "Debug/Production run",并且在运行单元测试时应该看到打印的消息 "Unit Testing Run"

您很可能必须添加代码以编程方式加载初始窗口,这个其他答案显示了如何做到这一点:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-21
    • 2019-04-03
    • 2017-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-23
    • 1970-01-01
    相关资源
    最近更新 更多