iOS Swift:为XCTest分离AppDelegate

Who*_*hoa 15 ios xctest swift

由于一些问题,我希望项目中的XCTest目标能够运行单独的应用程序委托.使用ObjC,这是一个相对简单的过程:操作main.m(参见:https://stackoverflow.com/a/15725328/1299041 ).

由于似乎@UIApplicationMain在AppDelegate中初始化了Swift应用程序,是否可以使用单独的AppDelegate为测试目标进行初始化?

Bar*_*nas 14

强烈建议在正常的代码检查中添加条件是否正在测试.相反,你应该嘲笑你AppDelegate的测试,做任何你想做的事情.

然后你可以替换UIApplication的委托是setUp你的每个XCTestCase人的超级类.

class MockAppDelegate:NSObject, UIApplicationDelegate {

}


class BaseTest: XCTestCase {

    override func setUp() {
        super.setUp()
        UIApplication.shared.delegate = MockAppDelegate()
       }
}
class Test1: BaseTest {

    override func setUp() {
        super.setUp()
        // normal testing
       }
}
Run Code Online (Sandbox Code Playgroud)

如果您仍想停止测试的代码执行,这是我的方法很好:

您可以向app添加启动参数,表明这是测试运行 App开始执行

可以从中访问这些参数 NSUserDefaults

#define IS_TESTS [[NSUserDefaults standardUserDefaults] boolForKey:@"TESTING"]
Run Code Online (Sandbox Code Playgroud)

  • 这不会阻止普通的app委托运行,不是吗?我的意思是,通常AppDelegate的`didFinishLaunchingWithOptions`在测试套件开始运行之前被触发. (5认同)
  • 这是一个好点,我同意避免在正常代码中添加测试相关条件.我实际上要做的是停止在主要的"AppDelegate"中执行代码(处理用户和会话状态以及数据存储).不幸的是,创建一个`MockAppDelegate`并没有实现这一点. (4认同)
  • @MichałHernas @Marc-AlexandreBérubé 我正在尝试这个,它运行正常的应用程序委托 - `setUp()` 在正常的应用程序委托运行 `didFinishLaunchingWithOptions` 之后执行。我的测试委托从未被使用过。 (2认同)

小智 5

要实现这一点,Swift 你需要采取几个步骤:

  1. 如果您使用的是 Storyboard,请在 AppDelegate 上以编程方式创建视图堆栈。

    从您的项目配置中 删除Main.storyboard项目配置

    从 AppDelegate 的开头删除@UIApplicationMain并添加此代码。

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
       let storyboard = UIStoryboard(name: "Main", bundle: nil)
       let vc = storyboard.instantiateInitialViewController()
    
       let window = UIWindow(frame: UIScreen.main.bounds)
       window.rootViewController = vc
    
       window.makeKeyAndVisible()
       self.window = window
    
       return true
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在目标的根目录创建一个新文件并将其命名为 main.swift

    如果您不需要为测试进行任何设置,请添加此代码

    import UIKit
    
    let kIsRunningTests = NSClassFromString("XCTestCase") != nil
    let kAppDelegateClass = kIsRunningTests ? nil : NSStringFromClass(AppDelegate.self)
    
    UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, kAppDelegateClass)
    
    Run Code Online (Sandbox Code Playgroud)

    如果您需要在运行测试之前进行一些配置,请创建一个新类FakeAppDelegate作为NSObject的子类,并在那里添加您的设置代码。

    将此代码放在main.swift 中

    import UIKit
    
    let kIsRunningTests = NSClassFromString("XCTestCase") != nil
    let kAppDelegateClass = kIsRunningTests ? NSStringFromClass(FakeAppDelegate.self) : NSStringFromClass(AppDelegate.self)
    
    UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, kAppDelegateClass)
    
    Run Code Online (Sandbox Code Playgroud)