6

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.

asked Feb 5, 2015 at 23:35
5
  • Could you parameterize [NSUserDefaults standardUserDefaults]? Make it something that can be set by the test, so what you're actually writing to, while testing, is some kind of mock? Commented Feb 5, 2015 at 23:53
  • I assume the answer involves mocking out NSUserDefaults. I even found an SO user that felt the need to write their own mock for that class. Commented Feb 5, 2015 at 23:54
  • So a dependency injection setup where any class wanting to update dateLastSynced had to pass in [NSUserDefaults standardDefaults]. And in my test, pass in a mock NSUserDefaults object? I'll try it Commented Feb 5, 2015 at 23:55
  • Neat, I'll check that out too Commented Feb 5, 2015 at 23:56
  • You say that you are using TDD. But then, how do you know that your method even needs to interact with system files? In TDD, the tests drive your design. So, either you already have a test that forces you to interact with system files, in which case you already have the answer to your question, or you don't have such a test, but then you cannot know that you need to interact with system files, because the only that you would know that would be if you had a test that told you so. Commented Feb 6, 2015 at 16:49

1 Answer 1

5

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.
answered Feb 11, 2015 at 21:18

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.