I am trying to mock UserDefaults to be able to test its behaviour.
What is the best way to do it without corrupting the real computed property that save the user token key?
class UserDefaultsService {
private struct Keys {
static let token = "partageTokenKey"
}
//MARK: - Save or retrieve the user token
static var token: String? {
get {
return UserDefaults.standard.string(
forKey: Keys.token)
}
set {
UserDefaults.standard.set(
newValue, forKey: Keys.token)
}
}
}
One way of doing it is to wrap your
UserDefaultsin a protocol and expose what you need.Then you create a an actual class which conforms to that protocol and which uses
UserDefaultsYou can then instantiate your
UserDefaultsServicewith that class.When you need to test, you can create a mock conforming to the same protocol and use that instead. That way you won't "pollute" your
UserDefaults.The above might seem like a bit of a mouthful so lets break it down.
Note that in the above I removed the "static" part as well, it didn't seem necessary, and it made it easier without it, hope that is OK
1. Create a Protocol
This should be all you are interested in exposing
2. Create an Actual Class
This class will be used with
UserDefaultsbut it is "hidden" behind the protocol.3. Instantiate UserDefaultsService With That Class
Now we create an instance of your
UserDefaultsServicewhich has an object conforming to theSettingsContainerprotocol.The beauty is that you can change the provided class later on...for instance when testing.
The
UserDefaultsServicedoes not know - or care - whatever theSettingsContaineractually does with the value, as long as it can give and take atoken, then theUserDefaultsServiceis happy.Here's how that looks, note that we are passing a default parameter, so we don't even have to pass a
SettingsContainerunless we have to.You can now use a new
UserDefaultsServicelike so:4 Testing
"Finally" you say :)
To test the above, you can create a
MockSettingsContainerconforming to theSettingsContainerand pass that to a new
UserDefaultsServiceinstance in your test target.And can now test that your
UserDefaultsServicecan actually save and retrieve data without pollutingUserDefaults.Final Notes
The above might seem like a lot of work, but the important thing to understand is:
UserDefaults) behind a protocol so you are free to change them later on if so needed (for instance when testing).Hope that helps.