3

In my XCode project I have:

  • controller
  • (Singleton) databaseController

The databaseController is instantiated within the controller class.

How do I replace this databaseController with a mock object to verify proper functioning of the controller class without being dependent on the actual databaseController?

notes:
- OCUnit is used for unit testing.
- OCMock is used for creating Mock objects.

Bonus question: What if the databaseController wasn't a singleton?

  • I think your "what if the databaseController wasn't a singleton" is too vague a question without knowing more about your application's requirements. – Christopher Pickslay Jun 30 '12 at 16:31

1 Answers1

2

This is the approach I've been taking. In your singleton:

static SomeManager *_sharedInstance = nil;

+(SomeManager *)sharedInstance {
    if (_sharedInstance == nil) {
        _sharedInstance = [[SomeManager alloc] init];
    }
    return _sharedInstance;
}

+(void)setSharedInstance:(SomeManager *)instance {
    _sharedInstance = instance;
}

Then, in your test:

-(void)testSomethingThatUsesSingleton {
    id mockManager = [OCMockObject mockForClass:[SomeManager class]];
    [SomeManager setSharedInstance:mockManager];
    [[mockManager expect] something];

    [controller doSomething];

    [mockManager verify];
    [SomeManager setSharedInstance:nil];
}

Don't forget to set the singleton back to nil at the end of your test. I generally do this in the tearDown in my unit test base class, so it automatically happens after each test.

Alternatively, you can create a category in your unit tests that overrides sharedInstance to return a mock object.

Christopher Pickslay
  • 17,523
  • 6
  • 79
  • 92
  • This works for the Singleton object. I'm still puzzling with mock objects in general, but I'll try to figure it out on my own. Thx for the help! – Wouter Scholtens Jul 03 '12 at 11:21
  • It might be helpful to read up on Dependency Injection. One of the main reasons that pattern came about was that people tried to use mock objects for testing and ran into the exact problem you encountered. And, yes, the answer is: don't instatiate the databaseController in the controller, make it possible to set which databaseController to use. – Erik Doernenburg Jul 03 '12 at 15:50