Testing UserDefaults

Want separate data from standardDefaults.

Mocking UserDefaults

How do you mock UserDefaults in your unit tests? What we use in our app to store and fetch data is UserDefaults.standard . We know this is system provided singleton. Data we generate in simulator will be stored here. What if we want a totally clean UserDefaults ?

This is how I do it:

class MockUserDefaults : UserDefaults {

convenience init() {
self.init(suiteName: "Mock User Defaults")!
}

override init?(suiteName suitename: String?) {
UserDefaults().removePersistentDomain(forName: suitename!)
super.init(suiteName: suitename)
}

}

Make another class called MockUserDefaults that subclass UserDefaults. It will create a new UserDefaults with given suitName. The special thing here is that we will first remove the persistent domain for suit name, after that, create a brand new and clean UserDefaults.

This is only when you need to test whether data is correctly stored to UserDefaults or not.

Test Interaction, not behavior

According to RayWenderlich’s Unit Testing Tutorial: Mocking Objects.

When you replace Apple’s classes with mocks, it’s very important to only test the interaction with that class, not the behavior of that class, as implementation details could change at any point.

Let’s said you have a button click that increase a number that is stored inside UserDefaults. If you want to test this, it is better to first subclass UserDefaults and create a new class like this.

class MockUserDefaults : UserDefaults {
var numberIncreased = false
override func setInteger(value: Int, forKey defaultName: String) {
if defaultName == "increasing number" {
numberIncreased = true
}
}
}

In your unit test, after button click to increase number then you set the increased number using setInteger method, you will notice that numberIncreased has been set to true. That means setInteger is getting called once. This is how you test the interaction instead of testing the class behavior.


I am not sure which way to test UserDefaults is better or best way. It really depends on the situation you are testing. If you have a better way to test UserDefaults, please leave a comment. :)