gas*_*sho 5 ios swift property-wrapper
假设我有一个使用 的属性包装器的非常常见的用例UserDefaults。
@propertyWrapper
struct DefaultsStorage<Value> {
private let key: String
private let storage: UserDefaults
var wrappedValue: Value? {
get {
guard let value = storage.value(forKey: key) as? Value else {
return nil
}
return value
}
nonmutating set {
storage.setValue(newValue, forKey: key)
}
}
init(key: String, storage: UserDefaults = .standard) {
self.key = key
self.storage = storage
}
}
Run Code Online (Sandbox Code Playgroud)
我现在声明一个对象,该对象将保存存储在UserDefaults.
struct UserDefaultsStorage {
@DefaultsStorage(key: "userName")
var userName: String?
}
Run Code Online (Sandbox Code Playgroud)
现在,当我想在某个地方使用它时,比如说在视图模型中,我会有这样的东西。
final class ViewModel {
func getUserName() -> String? {
UserDefaultsStorage().userName
}
}
Run Code Online (Sandbox Code Playgroud)
这里几乎没有什么问题。
.standard用户默认值。如何使用其他/模拟实例来测试该视图模型UserDefaults?UserDefaults?我是否必须创建一个新类型,它是上述类型的干净副本DefaultsStorage,通过模拟UserDefaults并测试该对象?struct TestUserDefaultsStorage {
@DefaultsStorage(key: "userName", storage: UserDefaults(suiteName: #file)!)
var userName: String?
}
Run Code Online (Sandbox Code Playgroud)
正如 @mat 在评论中已经提到的,您需要一个protocol模拟UserDefaults依赖项。像这样的事情会做:
protocol UserDefaultsStorage {
func value(forKey key: String) -> Any?
func setValue(_ value: Any?, forKey key: String)
}
extension UserDefaults: UserDefaultsStorage {}
Run Code Online (Sandbox Code Playgroud)
然后您可以更改DefaultsStoragepropertyWrapper 以使用UserDefaultsStorage引用而不是UserDefaults:
@propertyWrapper
struct DefaultsStorage<Value> {
private let key: String
private let storage: UserDefaultsStorage
var wrappedValue: Value? {
get {
return storage.value(forKey: key) as? Value
}
nonmutating set {
storage.setValue(newValue, forKey: key)
}
}
init(key: String, storage: UserDefaultsStorage = UserDefaults.standard) {
self.key = key
self.storage = storage
}
}
Run Code Online (Sandbox Code Playgroud)
之后模拟UserDefaultsStorage可能如下所示:
class UserDefaultsStorageMock: UserDefaultsStorage {
var values: [String: Any]
init(values: [String: Any] = [:]) {
self.values = values
}
func value(forKey key: String) -> Any? {
return values[key]
}
func setValue(_ value: Any?, forKey key: String) {
values[key] = value
}
}
Run Code Online (Sandbox Code Playgroud)
为了测试DefaultsStorage,传递一个实例UserDefaultsStorageMock作为其存储参数:
import XCTest
class DefaultsStorageTests: XCTestCase {
class TestUserDefaultsStorage {
@DefaultsStorage(
key: "userName",
storage: UserDefaultsStorageMock(values: ["userName": "TestUsername"])
)
var userName: String?
}
func test_userName() {
let testUserDefaultsStorage = TestUserDefaultsStorage()
XCTAssertEqual(testUserDefaultsStorage.userName, "TestUsername")
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1978 次 |
| 最近记录: |