我正在测试一个依赖于 UserDefaults 实例的类。在遵循here找到的示例代码中,我像这样创建和设置实例:
override func setUp() {
super.setUp()
defaults = UserDefaults(suiteName: #file)
defaults.removePersistentDomain(forName: #file)
}
运行测试后,将在与该测试类相同的目录中创建一个 plist 文件。如果我的测试文件名为
TestFile.swift
,则 plist 的名称为 TestFile.swift.plist
。我很确定这是在调用上面的 suiteName:
初始化程序时生成的。我的问题是:测试完成后如何删除该文件?我尝试在测试的 removeSuite(named: #file)
方法中调用 removeVolatileDomain(forName: #file)
、removePersistentDomain(forName: #file)
和 tearDown
,但没有成功。打电话synchronize()
似乎也没有帮助。
UserDefaults
的实际实例,而是传递不需要清理的不同类型的对象。 一个简单的例子如下:
class UnitTestDefaults: UserDefaults {
private var values = [String: Any]()
// override only the functions you need, e.g.
override func object(forKey defaultName: String) -> Any? {
values[defaultName]
}
override func set(_ value: Any?, forKey defaultName: String) {
values[defaultName] = value
}
}
或者,您可以定义一个新协议,并让您正在测试的对象依赖于该协议的实例,而不是UserDefaults
。 这将被认为是更适合单元测试的做法,并且如果简单地创建
UserDefaults
的实例(即使是没有定义自定义套件的子类)仍然会产生不需要的副作用,也可以解决您的问题。
protocol DefaultsStorage {
func object(forKey defaultName: String) -> Any?
func set(_ value: Any?, forKey defaultName: String)
}
class UnitTestDefaults: DefaultsStorage {
// ...
}
如果您想确保在运行之间保持干净的状态,那么在拆卸时将其清零可能是个好主意。
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
try super.tearDownWithError()
mockDefaults()
}
这里 mockDefaults()
调用传递
nil
的值,它会生成一个带有以下内容的 plist:
<plist version="1.0">
<dict/>
</plist>
它叫:
private extension FakeInrangeTests {
func mockDefaults(value: Bool? = nil) -> UserDefaults {
MockDefaults.makeInrange(#file, value)
}
}
哪个电话:
struct MockDefaults {
static func make(
_ file: String,
value: Any? = nil,
key: String?
) -> UserDefaults {
let userDefaults = UserDefaults(suiteName: file)!
userDefaults.removePersistentDomain(forName: file)
if let value = value, let key = key {
userDefaults.setValue(value, forKey: key)
}
return userDefaults
}
}
extension MockDefaults {
static func makeInrange(
_ file: String,
_ value: Bool?
) -> UserDefaults {
MockDefaults.make(
file,
value: value,
key: UserDefaults.fakeInrangeKey
)
}
}
您可以将其添加到您的 .gitignore。
*.swift.plist
var defaults: UserDefaults!
override func setUpWithError() throws {
continueAfterFailure = false
try super.setUpWithError()
defaults = UserDefaults(suiteName: #file)
defaults.setValue(12, forKey: "myKey")
}
override func tearDownWithError() throws {
try super.tearDownWithError()
defaults.removePersistentDomain(forName: #file)
}
suiteName
更改为字符串文字,而不是
#file
。我不清楚为什么,但使用
#file
(应该只解析为您的文件名)的行为与传递字符串常量不同。我还建议在
removePersistentDomain
中致电
tearDown
:
override func setUp() {
super.setUp()
defaults = UserDefaults(suiteName: "MyTestClass")
}
override func tearDown() {
super.tearDown()
defaults.removePersistentDomain(forName: "MyTestClass")
…
}