Class Mocks in Kiwi

Having been working with OCUnit and OCMock for awhile now, one of the common problems that I’ve run into is the pervasive use of code that breaks the “Tell, don’t ask” rule. For example, the following code is typical for retrieving a persisted user default:

NSString *myValue = [[NSUserDefaults standardUserDefaults] 
                     stringForKey:@"my_key"];

This code is calling a class method on NSUserDefaults. So how does one mock the returned value, and or verify that this code is being made correctly, using the correct key, etc?

To date, my approach has been to extract this one-line code to a separate method that returns the value. For example:

   ...
[self getMyDefault];
...
- (NSString *)getMyDefault {
  return [[NSUserDefaults standardUserDefaults] 
          stringForKey:@"my_key"];
}

This is ok, and allows testing the calling method using either a partial mock or subclass and override. But how do we then verify that the new getMyDefault┬ácalled method is working? Up until recently, I’ve been ignoring testing the new method, because there didn’t appear to be a reasonable way to do so. But in Kiwi, this is really easy:

it(@"gets the persisted user default", ^{
    id mockNSDefaults = [NSUserDefaults mock];
    [[NSUserDefaults stubAndReturn:mockNSDefaults] 
                     standardUserDefaults];
    [[mockNSDefaults should] receive:@selector(stringForKey:)
                           andReturn:@"my expected value"
                       withArguments:@"my_key"];
    [[[myObject getMyDefault] should] equal:@"my expected value"];
});

And voila! The above method creates a mock NSUserDefaults object, then uses Class method stubbing to return it when [NSUserDefaults standardUserDefaults] is called.

 

Kiwi has great support for mocking Class methods, as shown above. Refer to the Kiwi website for more details.

Leave a Reply