Category Archives: OCMock

Mock objects in general, and the OCMock framework specifically.

Need-Driven Development

I recently came across a 10 year old article titled “Mock Roles, not Objects“. I recall reading this article at some time in the past, but I guess that I really didn’t get it the first time. This article is awesome, and I recommend reading it. But maybe like me, you need to become fairly familiar with TDD and using mock objects before it will have much impact on your thinking.

When I reread the article, I was immediately struck by the opening 2 sentences:

“Mock Objects is an extension to Test-Driven Development that supports good Object-Oriented design by guiding the discovery of a coherent system of types within a code base. It turns out to be less interesting as a technique for isolating tests from third-party libraries than is widely thought.”

Wow. The article then goes on to explain how the proper use of Need-Driven Development can help in the creation of good, clean architecture. I think that maybe the first time I read this article, I was still stuck in creating relatively few, large objects with lots of methods. After repeated viewings of Uncle Bob’s videos though, I changed my mindset to using lots of small, SRP compliant objects. Without that mindset, it might be possible to misinterpret this article as recommending the use of partial mocks to intercept calls from one method to another within the same object. Been there, done that, got help and am hopefully on the road to recovery now.

I think that there are still parts of this article that I’m not evolved enough yet to fully grok, for example section 4.1. I think I’ll come back and reread the article in another year or so and see if I get it then.

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.

Looking at Other Unit Test Tools: OCHamcrest, OCMockito, and Kiwi

I’ve recently started looking at other unit testing frameworks. I’ve been using OCUnit, GHUnit, and OCMock. But I’m finding that as my tests become more extensive and numerous, the tests themselves are becoming more difficult to read. I have been able to test everything that I’ve tried using these tools, but the resulting test code is sometimes hard to read. So my objective in looking at other tools is not for additional functionality, but for better readability.

The first tools that I looked at were OCHamcrest and OCMockito by Jon Reid. I like the syntax provided by these. But I ran into a problem when converting some of my tests because they currently use partial mocks. It appears that the Java version Mockito provides something like partial mocks, using what is called “spy”, but that this capability hasn’t been ported to OCMockito yet.

So while contemplating whether to try pushing forward using categories, swizzling, or subclassing to replace partial mocks, another iOS engineer recommended that I give Kiwi a look. So I did, and it looks very promising. I guess I haven’t given Kiwi a good look before because I heard that it was only for BDD, not unit testing. This turns out not to be the case.

I am going to give Kiwi a workout by converting the tests in one of the existing unit test files in What’s My Speed: the WeatherService. This file contains an assortment of OCUnit tests using both mock and partial mock OCMock objects.

Adding Kiwi to the project and file

The first step is to add Kiwi to the project. I’m going to just add the static library and headers, but there are instructions for adding it as a subproject. I built the code from source following the instructions on the Kiwi website. I then added the static lib and headers to the project, added the Kiwi headers directory to the test target headers search path, and then the kiwi.h to the WeatherServiceTests.m file:

#import "Kiwi.h"

I’m going to try leaving OCMock in the file until all of the tests have been completed. Then rebuild to verify everything ok.

Note: I had to clean and build twice before it would build without errors. This is a long time Xcode bug. Sometimes Xcode appears to cache things. Upon making changes to header paths and such, it sometimes takes a couple builds before strange errors go away. In this case, it was reporting that it couldn’t find WeatherService.h. Build cleaning and rebuilding twice and the reported error went away.

I also encountered an error with missing header files, including NSObject+KiwiSpyAdditions.h. It appears that building Kiwi inside the Xcode IDE results in only part of the header files being copied to the build directory. I fixed this by manually copying the headers from the Kiwi/Kiwi source directory to my project’s Kiwi headers directory.

Converting the first few simple tests

Next I’ll convert the first few tests. These are simple tests that verify the basic singleton operation of the object. So here is the existing tests before converting. I’ve removed some lines that aren’t related to these tests, and I’ll add them back as we go.

#import <SenTestingKit/SenTestingKit.h>
#import <OCMock/OCMock.h>
#import "WeatherService.h"
#import "WeatherService-Private.h"

@interface WeatherServiceTests : SenTestCase

@property (nonatomic, strong) WeatherServiceForTesting *weatherService;

@end

@implementation WeatherServiceTests

- (void)setUp {    
    self.weatherService = [[WeatherServiceForTesting alloc]init];
}

- (void)tearDown {
    self.weatherService = nil;
}

- (void)testInstantiation {
    STAssertNotNil(self.weatherService, @"Test instance is nil");
}

- (void)testSharedInstanceNotNil {
    WeatherService *ws = [WeatherService sharedInstance];
    STAssertNotNil(ws, @"sharedInstance is nil");
}

- (void)testSharedInstanceReturnsSameSingletonObject {
    WeatherService *ws1 = [WeatherService sharedInstance];
    WeatherService *ws2 = [WeatherService sharedInstance];
    STAssertEquals(ws1, ws2, @"sharedInstance didn't return same object twice");
}

Ok, pretty straight forward tests, no mocks needed. Let’s convert these to Kiwi:

#import <SenTestingKit/SenTestingKit.h>
#import <OCMock/OCMock.h>
#import "WeatherService.h"
#import "WeatherService-Private.h"
#import "Kiwi.h"

SPEC_BEGIN(WeatherServiceKiwiTests)

describe(@"Singleton (by choice)", ^{

    it(@"should instantiate using init", ^ {

        [[[WeatherService alloc]init] shouldNotBeNil];
    });

    it(@"should instantiate using sharedInstance", ^{
        [[WeatherService sharedInstance] shouldNotBeNil];
    });

    it(@"should return the same instance twice using sharedInstance", ^{
        WeatherService *a = [WeatherService sharedInstance];
        WeatherService *b = [WeatherService sharedInstance];
        [[a should] beIdenticalTo:b];
    });

    it(@"should not return the same instance twice using init", ^{
        WeatherService *a = [[WeatherService alloc] init];
        WeatherService *b = [[WeatherService alloc] init];
        [[a shouldNot] beIdenticalTo:b];
    });

});
SPEC_END

Now let’s test to make sure the tests are actually working. Cmd+U to execute tests, and everything appears ok. Are the tests actually working? To verify this, I reverse the test logic by replacing “should” with “shouldNot”, and “ShouldNotBeNil” with “shouldBeNil”, rerunning the tests I see the failures. So I have some confidence that the tests are doing what I expect them to be doing.

Our next test methods further verify that init is doing what we expect. It calls 2 other methods, that each do just one thing.

- (WeatherService *)init {
    self = [super init];
    if (self) {
        [self startTimer];
        [self updateWeatherInfoForZipcode:kDEFAULT_ZIPCODE];
    }
    return self;
}

Ok, so with OCMock we used a partial mock in two tests:

- (void)testInitCallsStartTimer {
    id mock = [OCMockObject partialMockForObject:self.weatherService];
    [[mock expect]startTimer];
    id __unused initedMock = [mock init];
    [mock verify];
}
- (void)testInitCallsUpdateWeatherInfoForZipcode {
    id mock = [OCMockObject partialMockForObject:self.weatherService];
    [[mock expect]updateWeatherInfoForZipcode:kDEFAULT_ZIPCODE];
    id __unused initedMock = [mock init];
    [mock verify];
}

Since Kiwi appears to have great support mocks, this should be pretty straight forward. Note that Kiwi’s mock support allows defining stubs and expectations on both mocks and objects. This eliminates the need for partial mocks altogether!.

describe(@"init", ^{

    it(@"starts the timer", ^ {
        id weatherService = [[WeatherService alloc]init];
        [[weatherService should] receive:@selector(startTimer)];
        id __unused initedMock = [weatherService init];
    });

    it(@"updates the weather info", ^{
        id weatherService = [[WeatherService alloc]init];
        [[weatherService should] receive:@selector(updateWeatherInfoForZipcode:) withArguments:kDEFAULT_ZIPCODE];
        id __unused initedMock = [weatherService init];
    });

});

Ok, this new code looks pretty similar. It’s shorter by one line because [mock verify] isn’t needed. And for this small set of fairly simple tests, the difference in readability isn’t much, but I’m seeing the potential for greatly improved readability. The structure of the tests feels much more organized. I need to learn how to really take advantage of that. I’m going to stop this blog here, and continue converting the rest of the tests to Kiwi. I’ll probably have more to say about this in future posts as I learn more about using Kiwi.

How to Test Calls to Super

It is quite common in iOS object methods to include a call to the parent object using a construct like [super …]. This call is important, albeit simple. So how do we verify in our unit tests that this call is made?

For example, let’s look at testing the default implementation of UIViewController didReceiveMemoryWarning;

@interface ViewController : UIViewController
...
@end
@implementation ViewController
...
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
    ...
}

When I first started looking at this problem, there appeared to be 3 obvious ways to test this:

  1. Using a Category to Intercept Calls to Super
  2. Using a Category on a Subclass of the Parent to Intercept Calls to Super
  3. Swizzling

1: Using a Category to Intercept Calls to Super

The first approach is to use a category on the parent class to intercept the call to super’s method. It could then set a global flag to be inspected by the unit test.

#import "ViewController.h"

BOOL superWasCalled = NO;

@interface UIViewController (OverrideSuperForTesting)
- (void)didReceiveMemoryWarning;
@end
@implementation UIViewController (OverrideSuperForTesting)
- (void)didReceiveMemoryWarning {    
    superWasCalled = YES;    
}
@end

@interface ViewControllerTests : SenTestCase
@property (strong, nonatomic) ViewController *vc;
@end

@implementation ViewControllerTests
- (void)setUp {
    self.vc = [[ViewController alloc]init];
}
- (void)tearDown {
    self.vc = nil;
}

- (void)testDidReceiveMemoryWarningCallsSuper {
    [self.vc didReceiveMemoryWarning];
    STAssertTrue(superWasCalled, @"super not called");
}
@end

There are two issues with doing it this way:

  1. This code does not actually call super’s implementation of the method, which is probably ok for unit testing. The category’s method replaces the original implementation, which is simply lost.
  2. It does not work if the parent method being called is implemented as a category. Only one category will be called, and which one is unpredictable.

2: Using a Category on a Subclass of the Parent to Intercept Calls to Super

This second approach violates one of my testing rules: don’t modify product code just for testing. But this approach works, and is fairly clean. The only difference between this approach and the first one is that an empty subclass is created between the class and its parent. This allows creating a category on the empty class, which can then still call its super.

// Create an empty subclass
@interface ViewControllerSubclass : UIViewController
@end

@implementation ViewControllerSubclass
@end

// Change ViewController to use the subclass instead of UIViewController
@interface ViewController : ViewControllerSubclass
...
@end
#import "ViewController.h"

BOOL superWasCalled = NO;

@interface ViewControllerSubclass (OverrideSuperForTesting)
- (void)didReceiveMemoryWarning;
@end
@implementation ViewControllerSubclass (OverrideSuperForTesting)
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    superWasCalled = YES;    
}
@end

@interface ViewControllerTests : SenTestCase
@property (strong, nonatomic) ViewControllerSubclass *vc;
@end

@implementation ViewControllerTests
- (void)setUp {
    self.vc = [[ViewControllerSubclass alloc]init];
}
- (void)tearDown {
    self.vc = nil;
}

- (void)testDidReceiveMemoryWarningCallsSuper {
    [self.vc didReceiveMemoryWarning];
    STAssertTrue(superWasCalled, @"super not called");
}
@end

I am assuming that the only change to the product code is the inclusion of an empty subclass between ViewController and UIViewController. During testing, a category is used to change the functionality of the subclass.

It might be tempting to put the code to set the test flag directly into the subclassed method instead of using a category, but then this code would be executed during normal product runtime. I recommend against littering up product code with things that are there solely for testing. Separating test code into test files keeps the product code more readable.

3: Using Swizzling to Intercept Calls to Super

The third approach is to swizzle the method on the parent class. Swizzling is a fairly common practice, but is generally considered to be a hack. Using swizzling, we can redirect the call to the super’s method to any other method we want. In this case, a method that will set a flag to signal that it was called.

Perhaps the easiest way to do this is to use the open source JRSwizzle library. This simplifies the swizzle operations, and makes the code more readable. The down side of using JRSwizzle is that as of this writing, it isn’t unit tested, so code coverage metrics for your project will suffer some. But who knows, maybe somebody in the near future will add unit tests to it.

Like in method 2 above, we’ll subclass the parent, and intercept/swizzle calls to super there. We’ll use a category, so that the code doesn’t get included in product builds. This is optional though. The code could be put into the parent subclass, and just wouldn’t ever be called in product builds.

#import "JRSwizzle.h"

BOOL didReceiveMemoryWarningWasCalled = NO;

@interface ViewControllerTestable (ForTesting)
- (void)didReceiveMemoryWarningOverride;
@end

@implementation ViewControllerTestable (ForTesting)
- (void)didReceiveMemoryWarningOverride {
    // Call original. Swizzling will redirect this.
    [self didReceiveMemoryWarningOverride];
    didReceiveMemoryWarningWasCalled = YES;
}
@end

@implementation ViewControllerTests
...
- (void)testDidReceiveMemoryWarningCallsSuper {

    // Swizzle super's methods
    NSError *error;
    [ViewControllerTestable 
     jr_swizzleMethod:@selector(didReceiveMemoryWarning)
           withMethod:@selector(didReceiveMemoryWarningOverride)
                error:&error];
    [self.vc didReceiveMemoryWarning];
    STAssertTrue(didReceiveMemoryWarningWasCalled, 
                 @"didReceiveMemoryWarning did not call super");

    // Swizzle back
    [ViewControllerTestable 
      jr_swizzleMethod:@selector(didReceiveMemoryWarning)
            withMethod:@selector(didReceiveMemoryWarningOverride)
                 error:&error];
}
...

In this code, when our method under test calls [super didReceiveMemoryWarning], the call will actually be made to didReceiveMemoryWarningOverride. This in turn will set a flag, and call the original didReceiveMemoryWarning (using the swizzled didReceiveMemoryWarningOverride which now points to didReceiveMemoryWarning).

So what’s the best approach? That will depend on your specific test situation. The second approach seems the cleanest and safest. It does, however, complicate the product code, but only slightly.

Refactoring to Improve Testability

One of the observations that I made earlier is that refactoring for clean code as advocated by Robert C. Martin would greatly simplify unit testing. So let me give you an example, using some code I’m actually working with, not just something I threw together to support my argument.

This is from my personal motorcycle app that I use to display navigation, time, temp, and weather forecast while riding. I currently have a Weather model file that provides basic weather properties such as current temp. During initialization of this object, it needs to setup a timer to periodically check for any changes in the weather, as well as register to receive location notifications. This particular object was written long ago, before I became a 100% code coverage fanatic. I didn’t know how to test the init method back then. But now that I do, I’m going to refactor this code both to make Uncle Bob happy, as well as to add full unit test coverage for it.

So here’s the original init method:

Original code image

This code looks pretty typical for an init method, and there isn’t anything functionally wrong with it. Ignoring the NSLog statement, and standard call to super and return of self, it does 3 things:

  1. Set the default current location. Location is needed for getting local weather, and since I’m on a motorcycle, it will change periodically. I initialize it with a constant that is the zipcode where my home is located.
  2. Setup a timer to fire off every 5 minutes to update weather.
  3. Register to receive location change notifications from a Location object I also created.

I’ve used comments to identify what is happening on 2 of these things, the 3rd being so obvious I didn’t bother. However, I’ve learned over the past few years that comments should be considered smells. I believe that a better approach is to extract the commented code to a separate method, and name the method using the text from the comment. Let’s see how that also helps make unit testing easier.

Let’s extract the first thing to its own helper method: setLocationToDefault. We can use the refactor command as shown here:

Using refactor to extract a method

Following that, we’ll do the same thing for the other 2 things that init is doing. This results in the following refactored code:

Refactored init code

Now our code reads like prose, and the extracted helper methods do exactly what you would expect. These are 2 attributes of good code.

Create a class extension file to contain the declarations of the helper methods. This file can then be #imported in the unit test case file, but kept private to normal class users:

Prior to making these changes, our unit tests for init would require verifying that:

  1. The current location (lastLocation property) is set to our default value.
  2. The timer was set to callback every 5 minutes
  3. A location notification is set.

The first item is very easy to test. But the inclusion of the other 2 things in init could complicate and make the first test unreliable and/or outright fail. What if a side effect of the other 2 causes the current location to change? There is a potential race condition here. Even if it didn’t break at first, it might in the future as changes are made to the code. This code is fragile.

In this particular case, it probably isn’t a problem. But it shows the type of problem that unit testing can encounter whenever a method does multiple things. In Clean Code, Uncle Bob admonishes us to have each method do exactly 1 thing (the Curly principle?). That may sound a bit extreme, but look how it has simplified things here, and made things safer to extend or change later.

After refactoring, the unit tests for init can focus on making sure that it calls the methods that do these things, and not worry about exactly how they are done, how long it takes, or whether they have conflicting effects. We’ll use a partial mock object to do this, as shown here:

Init test using partial mock

In the code above, self.weather refers to the test weather object created in the setUp method. The partial mock created will intercept the expected calls, but pass anything else on to the test object. This code therefore tests only the code in the init method. The other unit tests that verify that the 3 things happen correctly would call the helper methods directly, thereby eliminating the possibility of any conflicting side effects.

Adding OCMock to a Project

OCMock is a framework for using mock objects in Objective-c projects. If you’re not familiar with mock objects, refer to mockobjects.com. For more detailed instructions, refer to the mock objects section in the Unit Testing iOS Applications in Xcode 4 course on lynda.com. The framework and source code are available on ocmock.org and also on github. Here are the basic steps for adding it to your project:

  1. Download the OCMock dmg file from the ocmock.org download page.
  2. Double-click the dmg file to extract the files from it.
  3. Add a Libraries group to your project at the top level.
  4. Select the Libraries group, and select Files -> Add Files to <project name> (or Cmd+Opt+A)
  5. Navigate to the OCMock files just downloaded. These will appear under “Devices” on the left.
  6. Select the libOCMock.a file and OCMock folder inside the iOS folder.
  7. Set the “Copy items into destination group’s folders” checkbox.
  8. Set the “Add to targets” checkboxes for the projects unit test target(s).
  9. Clear the main project executable target.
  10. Click Add.
  11. Open the build settings for the test target, and add “$(SRCROOT)/OCMock” to the Header Search Paths setting.
  12. Also add “$(SRCROOT)” to the Framework Search Path.
  13. Add -all_load to the Other Linker Flags build setting for the test target also.
And that’s it (at least as of Xcode 4.4.1).
Add #import OCMock.h to a test file to verify that the header search path is set correctly, and/or that you’ve copied the OCMock folder to your project correctly.
Instantiate a mock object in one of your test to verify that the everything is working.
   id mock = [OCMockObject mockForClass:NSObject.class];
If you get a link error when building the tests containing this, check that the libOCMock.lib file was copied to your project directory.