swift 用XCUIApplication.launchArguments覆盖Username会忽略对该键的所有未来更新,那么我如何测试它呢?

oknrviil  于 2023-10-15  发布在  Swift
关注(0)|答案(1)|浏览(104)

我可以通过使用XCUIApplication. launchArguments设置来成功覆盖UserObject值。但是根据这个链接和我注意到的行为,一旦我覆盖了Username值,应用程序试图对其进行的所有更改都会被忽略
如何为UserKey设置初始测试值,但仍允许我的应用更改该值?如何正确测试我的应用对UserMonitor更新的响应,并避免必须按顺序运行的UserMonitor测试?
更多背景/细节:在我的iOS应用程序中,我使用Username来指定如何呈现一些应该在应用程序会话中持久化的内容。示例:我有一个设置,可以跟踪用户是否想查看一天中的时间与闹钟的倒计时计时器(例如,显示“3:00 pm”vs“in 1 hour”)。让我们在UserController中使用键showClockTime将其称为布尔值。用户可以从设置UserController值的“设置”页面更改他们的首选项,而我的其他UIViewControllers会检查viewWillAppear()中的UserController值,以便显示正确的内容。
而不是在整个应用程序中添加相同的检查,如果这个布尔值是nil,true或false,我在SceneDelegate中检查它,如果值是nil,则将其设置为我喜欢的任何默认值,然后假设它在我的应用程序的其余部分中永远不会为nil。(我知道如果你使用UserDefaults.standard.bool("showClockTime"),布尔值默认返回false而不是nil,但是我也有一些String设置我想测试,所以就用它吧。
我正在尝试编写集成测试来测试:

  • 如果用户从未打开过应用程序,在他们看到第一个UIViewController之前,我是否在SceneDelegate中设置了正确的默认值?(意思是:如果值最初是nil,我想验证我是否将其设置为true,并且UI渲染为true设置,而不是默认的false,否则将是)
  • Username在测试运行中持续存在,因此要获得非Username测试,我如何设置测试的初始Username值,同时测试我的设置页面是否正确更新了该值。例如,我有一个开关,我想切换“关闭”(所以showClockTime = false),我需要知道它在我的测试运行之前是“打开”的(所以showClockTime必须最初是true,否则切换不会像我期望的那样)。

不知道这是否重要,但关于我的应用程序的其他信息:

  • 这是一个vanilla Swift应用程序,我没有使用任何库

尝试将Username键showClockTime设置为nil,因为它将首次启动应用程序,并且在测试运行后,我无法更改设置。

t40tm48m

t40tm48m1#

我找到了一个解决方案,但我不确定这是最好的方法:
重写UserList键只会使 that 键在测试的其余部分不可变,因此,重写测试键并在AppDelegate内将该重写转换为应该被重写的实际键。
在UI测试中:

// Assuming you want to override the actual "legitKeyName" in UserDefaults
extension XCUIApplication {
    
    func resetLegitFlag() {
        launchArguments += ["-isTestEnvironment", "true"]
        launchArguments += ["-testlegitKeyName", "nil"]
    }
    
}

在AppDelegate中:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
    if (UserDefaults.standard.bool(forKey: "isTestEnvironment")) {
        // We are in a test, check if we need to override a key
        let actualKeyName = "legitKeyName"
        let overrideValue = UserDefaults.standard.string(forKey: "test" + actualKeyName)
        
        if (overrideValue != nil) {
            switch overrideValue {
            case "nil":
                UserDefaults.standard.removeObject(forKey: actualKeyName)
                break
            default:
                UserDefaults.standard.set(overrideValue, forKey: actualKeyName)
            }
        }
    }

}

你可以为每个你想覆盖的标志这样做,但仍然在测试中改变。
在你的测试中:

final class LegitKeyUITests: XCTestCase {    
    
    override func setUpWithError() throws {
        let app = XCUIApplication()
        app.resetLegitFlag()
        app.launch()
        ...
    }
}

这对我的情况是有效的,但我不喜欢测试代码在AppDelegate中。我尝试通过添加第二个标志来降低prod中意外调用并更改真实的用户设置的风险,该标志指定这是一个测试。

相关问题