我目前正在为我的应用程序进行测试,并且在模拟用户默认值时遇到了问题。让我先向您展示我的设置:
这是我模拟用户默认值的方式:
class MockUserDefaults: UserDefaults {
typealias FakeData = Dictionary<String, Any?>
var data: FakeData
convenience init() {
self.init(suiteName: "mocking")!
}
override init?(suiteName suitename: String?) {
data = FakeDefaults()
UserDefaults().removePersistentDomain(forName: suitename!)
super.init(suiteName: suitename)
}
override func object(forKey defaultName: String) -> Any? {
if let data = data[defaultName] {
return data
}
return nil
}
override func set(_ value: Any?, forKey defaultName: String) {
if defaultName == "favs"{
data[defaultName] = value
}
}
}
我的视图控制器中有一个名为userDefaults的变量,我设置如下:
var userDefaults : UserDefaults {
if (NSClassFromString("XCTest") != nil) {
return MockUserDefaults()
}
return UserDefaults.standard
}
这个变量实际上是一个协议的扩展,uiviewcontroller使它符合它,以确保我的所有视图控制器都有这个变量。
我在myViewcontroller中也有一个名为favoriteMovie的变量,我设置如下:
private var favoriteMovie: Favorite? {
if let favoriteString = userDefaults.value(forKey: "favs") as? String {
return favorites.first(where: {$0.name == favoriteString})
}
return nil
}
现在问题出现了,当我去尝试测试这个视图控制器时,我需要设置userDefault一个对象,例如:
myviewController.userDefaults.set("avengers", forKey: "favs")
在测试运行之前,但问题是favoriteMovie变量总是返回nil,我需要它在测试运行之前返回一个对象。任何帮助。提前谢谢。
更新:
这是协议:
protocol Mockable: class {
var userDefaults: UserDefaults { get }
}
这是扩展名:
extension UIViewController: Mockable {}
extension Mockable {
var userDefaults : UserDefaults {
if (NSClassFromString("XCTest") != nil) {
return MockUserDefaults()
}
return UserDefaults.standard
}
}
答案 0 :(得分:0)
以下是两种解决方法。
1)通过做一些DI。在您viewController
中将userDefaults
声明为非计算属性,如下所示
var userDefaults : UserDefaults?
在您的测试用例中,创建MockUserDefaults
对象,设置值并在启动时将其分配给viewController
,如下所示
let mockUD = MockUserDefaults()
mockUD.set("avengers", forKey: "favs")
myviewController.userDefaults = mockUD
现在您将获得avengers
对象。
2)随着问题的更新,以下是保存mockDefaults
对象的修复方法,
struct AssociatedMock {
static var key: UInt8 = 0
}
extension Mockable {
private (set) var _mockDefaults: MockUserDefaults? {
get {
guard let value = objc_getAssociatedObject(self, &AssociatedMock.key) as? MockUserDefaults else {
return nil
}
return value
}
set(newValue) {
objc_setAssociatedObject(self, &AssociatedMock.key, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
var userDefaults : UserDefaults {
if (NSClassFromString("XCTest") != nil) {
if self._mockDefaults == nil {
self._mockDefaults = MockUserDefaults()
}
return self._mockDefaults!
}
return UserDefaults.standard
}
}