Handling UserDefaults in iOS UI Tests

Axel Hodler
2 min readJul 5, 2020
Image by Websi on Pixabay

We can use UserDefaults to store any basic data types. Bool, Int, String and more. The data is loaded when the app starts and removed when the application is deleted from the device.

One example where UserDefaults comes in handy is to mark wether the user has seen the tutorial. It allows us to not show it to the user again on any subsequent app start.

We store the value if the user has seenTutorial in a Bool.

UserDefaults.standard.set(true, forKey: "seenTutorial")

We want to write the following UI tests

  • Show tutorial on first launch
  • Don’t show tutorial if already seen

The first idea would be to write a test like.

It will even work once. It would also work once if we were not explicitly setting the seenTutorial here. It works until something or someone taps on the Continue button and stores the seenTutorial state in the application.

Apple states in the docs:

UI testing exercises your app’s UI in the same way that users do without access to your app’s internal methods, functions, and variables.

We cannot work with direct access to UserDefaults here.

Instead we define launchArguments of XCUIApplication like so

We use an extension to avoid unnecessary code that disturbs the reading flow in our tests. CallingsetSeenTutorial() marks seenTutorial as true. Calling setSeenTutorial(false) marks seenTutorial as false. Using the Objective-C Syntax of "YES" and "NO" works too here.

The test now looks as follows and passes

We can always add other assertions. Next we could add a test for what should happen after the user taps on the Continue button.

When finding the elements to use the assertion on it is helpful to use the Record UI Test feature of Xcode. We press the red recording button and click through the UI. The relevant code will be generated.

Record UI Test Feature

The code for the sample application is on Github. Additionally it shows how to use UserDefaults in combination with SwiftUI.

Our use case above is business logic. Business logic should usually be tested with a unit test. Not a UI test. Having the UI test too saves us the trouble of uninstalling and reinstalling the app again and again while trying to check if the functionality works. It makes everything reproducible. Especially if we are new to the intricacies of SwiftUI and Combine.

--

--

Axel Hodler

Building things. Usually by writing code. www.hodler.co. Software Engineering @porschedigital