运行单元测试时删除 UserDefaults 生成的 plist 文件

问题描述 投票:0回答:3

我正在测试一个依赖于 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()
似乎也没有帮助。

ios swift nsuserdefaults xctest userdefaults
3个回答
4
投票
理想情况下,您不应传递

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 { // ... }
    

1
投票
这是一个测试目标,因此不必担心提交它。一旦承诺一次,就无需再担心。

如果您想确保在运行之间保持干净的状态,那么在拆卸时将其清零可能是个好主意。

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


通过运行可以确认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) }
    

0
投票

suiteName

 更改为字符串文字,而不是 
#file
。我不清楚为什么,但使用 
#file
 (应该只解析为您的文件名)的行为与传递字符串常量不同。我还建议在 
removePersistentDomain
 中致电 
tearDown
:

override func setUp() { super.setUp() defaults = UserDefaults(suiteName: "MyTestClass") } override func tearDown() { super.tearDown() defaults.removePersistentDomain(forName: "MyTestClass") … }
    
© www.soinside.com 2019 - 2024. All rights reserved.