我想测试我的应用程序的行为,决定应用程序启动。例如:在标签栏控制器中,将创建多少和哪些标签是在应用程序启动时决定的,根窗口已经创建,所以我想为每个测试用例测试这些行为。
这个新功能是通过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)
}
}