ios - 如何在与默认目标中的数据不同的数据/应用程序(SQLite db、UserDefaults)上运行 Xcode 测试?

标签 ios swift xcode unit-testing

到目前为止,我已经通过在模拟器中运行来手动测试我的 iOS/Swift 项目。现在,我已将单元测试目标添加到项目中,以包含自动化测试。

我惊讶地发现,在模拟器中运行默认目标和运行测试目标都会影响相同的数据/相同的应用程序实例。

例如,使用 SQLite 数据库和 UserDefaults 来保存一些数据和设置。当将数据写入数据库或更改测试内 UserDefaults 中的设置时,这些更改在模拟器中运行应用程序时也可见(反之亦然)。

我认为因为测试是在单独的目标中,所以将使用单独的数据。事实并非如此。

是否可以将测试目标设置为不干扰应用目标?

最佳答案

背景

这肯定是一个很棒的功能,但目前还不可能。这是因为单元测试并不完全是一个完整的 iOS 应用程序目标。相反,它只是将主应用程序目标托管为被测系统并测试其代码。

下面是单元测试目标的“常规”设置选项卡的屏幕截图。看到它实际上托管主应用程序目标,而不是主应用程序目标的克隆/变体。

您可以使用以下代码来解决此限制,该代码检查应用程序是否正在进行单元测试。

extension UIApplication{
    
    var isTesting: Bool {
        #if DEBUG
        if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil {
            return true
        }
        return false
        #else
        return false
        #endif
    }
    
}

请注意,我添加了“#if DEBUG”条件编译标记,以防止在发布版本中评估进程信息。

下面我针对您的情况提出了两种解决方法。

SQLite 的解决方法

您可以使用此扩展来使用两个不同的数据库名称,具体取决于是否正在执行单元测试。

import SQLite

do {
    let dbName = UIApplication.shared.isTesting ? "db_test" : "db"

    let path = "path/to/\(dbName).sqlite"
    let db = try Connection(path)
    // ...
}
catch{
    print(error)
}

用户默认值的解决方法

使用两组数据进行正常应用执行和测试并不那么简单。建议的解决方法引入了两个与 UserDefaults 中的标准 setValuevalue 方法类似的新方法。这些特殊版本根据是否正在运行单元测试,在键后附加“_test”后缀。效果是正常设置不会被单元测试设置修改。

extension UserDefaults{
    
    private var testKeySuffix: String{
        return UIApplication.shared.isTesting ? "_test" : ""
    }
    
    func safeSetValue(_ value: Any?, forKey key: String){
        UserDefaults.standard.setValue(value, forKey: "\(key)\(testKeySuffix)")
    }
    
    func safeValue(forKey key: String) -> Any?{
        return UserDefaults.standard.value(forKey: "\(key)\(testKeySuffix)")
    }
    
}

上述扩展可以按如下方式使用。

// UserDefaults.standard.setValue("123", forKey: "myKey")
UserDefaults.standard.safeSetValue("123", forKey: "myKey")

// let str = UserDefaults.standard.value(forKey: "myKey")
let str = UserDefaults.standard.safeValue(forKey: "myKey")

关于ios - 如何在与默认目标中的数据不同的数据/应用程序(SQLite db、UserDefaults)上运行 Xcode 测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69452935/

相关文章:

ios - 在 swift firebase 中添加一个新的 child 后填充数组

swift - 复制自定义对象按值而不是按引用复制它

ios - Swift 3 转换器添加了 fileprivate 函数

objective-c - 过多的 UITableView 单元格

ios - 苹果加速框架——限制幅度而不损失绝对值

html - 从xcode中的数组加载本地html

android - 如何根据另一个小部件中的操作更新 UI 或更改小部件中的状态?

ios - UITableView 干扰状态栏

快速从文本中提取主题标签字符串

iphone - 如何将图像放到 iPad 模拟器上