如何使用模拟器在XCUITest中以编程方式清除NSUserDefaults

时间:2018-08-21 00:58:57

标签: ios objective-c xcuitest

我已经阅读了与此相关的几个答案,他们建议执行以下一项操作,但这些选项对我不起作用。我有一个XCUITest,在运行其余的XCUITest之前,我想先清除标准用户默认设置。目前,我的测试应用程序有一个调用此代码的按钮。我也尝试过直接从XCUITest内部调用此代码(我不确定这是否可以正常工作或是否需要从应用程序内部运行)。

NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];

我也尝试过分别删除它们:

[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"MyKey1"];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"MyKey2"];

我还尝试了上述每种方法,然后进行了同步调用:

[[NSUserDefaults standardUserDefaults] synchronize];

下次我从NSUserDefaults读取@“ MyKey1”时,它仍然具有旧值,并且尚未删除。

在模拟器中运行XCUITest时,是否可以通过编程方式从NSUserDefaults中删除对象?这些是自动化测试,因此我不能总是手动单击xcode中的“重置内容和设置”。

谢谢!

2 个答案:

答案 0 :(得分:5)

couple of ways可以通过在测试运行应用程序之前(而不是之后)设置UserDefaults值来解决您的问题。

解决方案#1

使用launchArguments模拟某些键的UserDefaults值:

func testExample() {
    let app = XCUIApplication()
    app.launchArguments += ["-keepScreenOnKey", "YES"]
    app.launch()
}

注意 keepScreenOnKey键之前的减号。减号表示应该将下一个启动参数值作为该UserDefaults键的值。

解决方案2(如果解决方案1不起作用)

如果您使用的是SwiftyUserDefaults库,则以前的解决方案可能不起作用。在这种情况下,有一个不错的解决方案:如果应用程序在UI测试下运行,请从应用程序中删除所有UserDefaults数据。应用程序如何知道它是否正在UI测试下运行?通过传递启动参数消息,如下所示:

override func setUp() {
    super.setUp()
    app.launchArguments += ["UI-Testing"]
}

然后,在AppDelegate.swift中检查应用程序是否在UI-Testing下运行,并删除所有UserDefaults数据(就像您一样):

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        setStateForUITesting()

        return true
    }

    static var isUITestingEnabled: Bool {
        get {
            return ProcessInfo.processInfo.arguments.contains("UI-Testing")
        }
    }

    private func setStateForUITesting() {
        if AppDelegate.isUITestingEnabled {
            UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
        }
    }
}

解决方案#3(如果解决方案#2不够)

但是,如果UI测试期望状态不是解决方案2设置的默认状态,该怎么办?布尔默认为false,整数默认为0,字符串默认为"",但是如果您需要true作为布尔键怎么办?

执行以下操作:

func testExample() {
    app.launchEnvironment["UI-TestingKey_keepScreenOn"] = "YES"
    app.launch()
}

然后在AppDelegate.swift文件中:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    static let uiTestingKeyPrefix = "UI-TestingKey_"

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        if AppDelegate.isUITestingEnabled {
            setUserDefaults()
        }

        return true
    }

    static var isUITestingEnabled: Bool {
        get {
            return ProcessInfo.processInfo.arguments.contains("UI-Testing")
        }
    }

    private func setUserDefaults() {
        for (key, value)
            in ProcessInfo.processInfo.environment
            where key.hasPrefix(AppDelegate.uiTestingKeyPrefix) {
            // Truncate "UI-TestingKey_" part
            let userDefaultsKey = key.truncateUITestingKey()
            switch value {
            case "YES":
                UserDefaults.standard.set(true, forKey: userDefaultsKey)
            case "NO":
                UserDefaults.standard.set(false, forKey: userDefaultsKey)
            default:
                UserDefaults.standard.set(value, forKey: userDefaultsKey)
            }
        }
    }
}

extension String {
    func truncateUITestingKey() -> String {
        if let range = self.range(of: AppDelegate.uiTestingKeyPrefix) {
            let userDefaultsKey = self[range.upperBound...]
            return String(userDefaultsKey)
        }
        return self
    }
}

请注意,此示例仅适用于Bool和String键。如果需要更高的可伸缩性,则应修改switch命令,以某种方式检查该值是Integer还是Double或任何其他值,但是一般的想法在这里。

EDIT:从SwiftyUserDefaults version 4.0.0-beta.1开始,似乎使用解决方案#2和#3的原因不再有效,因为它们已经添加了对通过启动参数设置值的支持。但是,我必须承认,从此版本开始,我还没有测试过SwiftyUserDefaults库,因此我将两种解决方案都保留在这里。

答案 1 :(得分:0)

通过UI测试,该应用程序作为单独的进程运行。您需要调用这些方法以从应用程序内部清除NSUserDefaults。

我们让我们的UI测试在启动应用程序时将resetNSUserDefaults标志传递给该应用程序。然后,应用程序会在启动过程的早期清除NSUserDefaults。