I'm testing a class that depends on an instance of UserDefaults. In following this sample code found here, I create and setup the instance like so:
override func setUp() {
super.setUp()
defaults = UserDefaults(suiteName: #file)
defaults.removePersistentDomain(forName: #file)
}
After running the tests, a plist file is created within the same directory as this test class. If my testing file is named TestFile.swift
the plist is given the name TestFile.swift.plist
. I'm pretty sure this is generated at the call of the suiteName:
initializer above. My question is: how do I remove this file once the tests have completed? I've tried making calls to removeSuite(named: #file)
, removeVolatileDomain(forName: #file)
, and removePersistentDomain(forName: #file)
within the test's tearDown
method but no luck. Calling synchronize()
didn't seem to help either.
Ideally, instead of passing in an actual instance of UserDefaults
, you would instead pass a different type of object that doesn't require that cleanup. A simple example would be something like:
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
}
}
Alternatively, you could define a new protocol and have the object you're testing depend on an instance of that protocol instead of UserDefaults
. This would be considered more proper practice for unit testing, and would also solve your problem if simply creating an instance of UserDefaults
, even a subclass that doesn't define a custom suite, still has unwanted side effects.
protocol DefaultsStorage {
func object(forKey defaultName: String) -> Any?
func set(_ value: Any?, forKey defaultName: String)
}
class UnitTestDefaults: DefaultsStorage {
// ...
}