我已经阅读了与此相关的几个答案,他们建议执行以下一项操作,但这些选项对我不起作用。我有一个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中的“重置内容和设置”。
谢谢!
答案 0 :(得分:5)
有couple of ways可以通过在测试运行应用程序之前(而不是之后)设置UserDefaults值来解决您的问题。
使用launchArguments
模拟某些键的UserDefaults值:
func testExample() {
let app = XCUIApplication()
app.launchArguments += ["-keepScreenOnKey", "YES"]
app.launch()
}
注意 keepScreenOnKey
键之前的减号。减号表示应该将下一个启动参数值作为该UserDefaults键的值。
如果您使用的是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!)
}
}
}
但是,如果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。