在AppDelegate中为每个或分离的单元和集成测试测试不同的行为



我想测试我的应用程序的行为,决定应用程序启动。例如:在标签栏控制器中,将创建多少和哪些标签是在应用程序启动时决定的,根窗口已经创建,所以我想为每个测试用例测试这些行为。

这个新功能是通过A/B服务设置的,并且只在应用启动时检索值。基于该值,选项卡栏的视图控制器被设置。

例如:

var viewControllers: [UIViewController] = [ tabOne, tabTwo]
if Config.isNewFeatureEnabled {
viewControllers.append(self._menuCoordinator.rootViewController)
} else {
viewControllers.append(self._anotherTabBarController)
viewControllers.append(self._anotherCoordinator.rootViewController)
viewControllers.append(self._someOtherCoordinator.rootViewController)
}
_tabBarController.viewControllers = viewControllers

让我把代码,为了使测试更容易,我创建了一个协议(不一定,但更好的方法注入)

protocol FeatureFlag {
var isNewFeatureEnabled: Bool { get set }
}
// Implementation
class FeatureFlagService: FeatureFlag {
var isNewFeatureEnabled = false
// Bunch of other feature flags
}

在我的测试用例中,我想切换配置而不影响应用程序的另一边。像这样:

class NewFeatureVisibilityTests: XCTestCase {
func test_TabBar_has_threeTabs_when_NewFeature_isEnabled() {
// Looking for a way to inject the config
let tabBar = getKeyWindow()?.rootViewController as? UITabBarController
guard let tabBar = appDel.currentWindow?.rootViewController as? UITabBarController else {
return XCTFail("Expected root view controller to be a tab bar controller")
}
XCTAssertEqual(tabBar.viewControllers?.count, 3)
}
func test_TabBar_has_fiveTabs_when_NewFeature_isDisabled() {
// Looking for a way to inject the config
let tabBar = getKeyWindow()?.rootViewController as? UITabBarController
guard let tabBar = appDel.currentWindow?.rootViewController as? UITabBarController else {
return XCTFail("Expected root view controller to be a tab bar controller")
}
XCTAssertEqual(tabBar.viewControllers?.count, 5)
}
}

我想要的是通过注入(配置等)为每个测试用例设置应用程序的行为。

一个测试功能将被启用,另一个测试将断言功能的禁用状态。

在AppDelegate中使用现有的FeatureFlag类型创建一个配置属性,并在override init上使用默认值。

extension UIApplication {
var currentWindow: UIWindow {
return (connectedScenes
.filter({$0.activationState == .foregroundActive})
.compactMap({$0 as? UIWindowScene})
.first?.windows
.filter({$0.isKeyWindow}).first!)!
}
}
@main
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?
let config: FeatureFlag!

override init() {
config = FeatureFlagService()
}

init(config: FeatureFlag!) {
self.config = config
}

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.

// Create a tabBar with 3 tabs
let tabBarController = UITabBarController()
let firstViewController = UIViewController()
let secondViewController = UIViewController()
let thirdViewController = UIViewController()
let fourthViewController = UIViewController()
let fifthViewController = UIViewController()

firstViewController.tabBarItem = UITabBarItem(tabBarSystemItem: .favorites, tag: 0)
secondViewController.tabBarItem = UITabBarItem(tabBarSystemItem: .downloads, tag: 1)
thirdViewController.tabBarItem = UITabBarItem(tabBarSystemItem: .more, tag: 2)
fourthViewController.tabBarItem = UITabBarItem(tabBarSystemItem: .bookmarks, tag: 3)
fifthViewController.tabBarItem = UITabBarItem(tabBarSystemItem: .contacts, tag: 4)

var viewControllers = [firstViewController, secondViewController]
if config.isNewFeatureEnabled {
viewControllers.append(thirdViewController)
} else {
viewControllers.append(fourthViewController)
viewControllers.append(fifthViewController)
}

tabBarController.viewControllers = viewControllers

// Create a window and set the root view controller
let window = UIWindow(frame: UIScreen.main.bounds)
window.rootViewController = tabBarController
window.makeKeyAndVisible()
self.window = window

return true
}
}

在测试中,我设置了我的配置,创建了AppDelegate的实例,注入了配置,并通过AppDelegate的appDelegate.application(UIApplication.shared, didFinishLaunchingWithOptions: nil)函数启动了应用程序。

let appDelegate = AppDelegate(config: config)
// This is the key function
_ = appDelegate.application(UIApplication.shared, didFinishLaunchingWithOptions: nil)

测试:

import XCTest
@testable import ExampleApp

final class NewFeatureVisibilityTests: XCTestCase {

func test_app_can_start_with_isNewFeatureEnabled(){
let config = FeatureFlagService()
config.isNewFeatureEnabled = true
let appDelegate = AppDelegate(config: config)
// This is the key function
_ = appDelegate.application(UIApplication.shared, didFinishLaunchingWithOptions: nil)

guard let rootVC = UIApplication.shared.currentWindow.rootViewController as? UITabBarController else {
return XCTFail("RootViewController is nil")
}

XCTAssertEqual(rootVC.viewControllers?.count, 3)
}

func test_app_can_start_with_isNewFeatureDisabled(){
let config = FeatureFlagService()
config.isNewFeatureEnabled = false
let appDelegate = AppDelegate(config: config)
// This is the key function
_ = appDelegate.application(UIApplication.shared, didFinishLaunchingWithOptions: nil)

guard let rootVC = UIApplication.shared.currentWindow.rootViewController as? UITabBarController else {
return XCTFail("RootViewController is nil")
}

XCTAssertEqual(rootVC.viewControllers?.count, 4)
}
}

最新更新