Unit Testing – How to Write Tests for Methods Interacting with System Files

iosobjective ctddtestingunit testing

I'm trying to be proactive about writing an iOS app in a test-driven manner. However, I'm stumped as to how to test a method that is to interact with real system files. For those familiar with iOS, I'm writing to the NSUserDefaults file.

Here's my set-up: I have a singleton called AppState that I am using to record when data downloaded from the Internet was last synced locally. Other classes can update the dateLastSynced property of AppState. I am overriding the setDateLastSynced method to save that update to the system so it's persisted between opening and closing the app:

- (void)setDateLastSynced:(NSDate *)dateLastSynced
{
    // update instance variable with new value
    _dateLastSynced = dateLastSynced;

    // store change to NSUserDefaults
    [[NSUserDefaults standardUserDefaults] setObject:dateLastSynced forKey:APP_STATE_DATE_LAST_SYNCED_KEY];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

I'd like to write a test that verifies that setDateLastSynced is working correctly – but I'm not sure how to do that without overwriting data already saved to the system in NSUserDefaults.

Best Answer

You have to mock or emulate, and you have two very good reasons to do so.

  1. You have to mock or emulate whatever parts of the system your code interacts with, precisely because:

    • You don't want to alter the system, and
    • You don't want your tests to depend on something as uncontrollable as the system.

       Yes, your emulation will not be perfect; yes, you will in fact be modelling your knowledge and assumptions about how the system works; and that's perfectly fine. You are essentially taking a spec and restating it in code: nothing wrong with that. The spec in this case is written by the creators of the operating system and not by you.

  2. You have to mock or emulate everything that deals with time, even your own stuff.

    • You have to be able to set the emulated clock time to a certain fake date, pretend that files are created/modified, and then check their creation/modification date and make sure it is the fake date, and all this without of course changing the system clock.
    • You also have to be able to check that a certain date in the future is correctly set, or that something happens at that moment in time, all during the execution of a single test, without having to wait for real time to advance.