Lazloman
Lazloman

Reputation: 41

Testing NSWidowController using OCMock

I've been trying to come up with a a way to unit test my applicationDidFinishLaunching delegate using OCMock. My NSWindowController is instantiated here and I'd like to test it. Here's my test code:

id mockWindowController = [OCMockObject niceMockForClass:[URLTimerWindowController class]];
[[mockWindowController expect] showWindow:self];
NSUInteger preRetainCount = [mockWindowController retainCount];

[appDelegate applicationDidFinishLaunching:nil];

[mockWindowController verify];

When I run the test, I get the error:

"OCMockObject[URLTimerWindowController]: expected method was not invoked: showWindow:-[URLTimerAppDelegateTests testApplicationDidFinishLaunching]"

The log gives more detail:

"Test Case '-[URLTimerAppDelegateTests testApplicationDidFinishLaunching]' started.
2011-04-11 08:36:57.558 otest-x86_64[3868:903] -[URLTimerWindowController loadWindow]: failed to load window nib file 'TimerWindow'.
Unknown.m:0: error: -[URLTimerAppDelegateTests testApplicationDidFinishLaunching] : OCMockObject[URLTimerWindowController]: expected method was not invoked: showWindow:-[URLTimerAppDelegateTests testApplicationDidFinishLaunching]
Test Case '-[URLTimerAppDelegateTests testApplicationDidFinishLaunching]' failed (0.005 seconds).
"

So I see that the NIB fails to load. Ok, so how do I make it load while unit testing or somehow mock its load? I've already looked at the OCMock docs, Chris Hanson's tips on unit testing and a few other resources, including the WhereIsMyMac source code which behave in a similar fashion. My application for instantiating the window controller is this:

self.urlTimerWindowController = [[URLTimerWindowController alloc] init];
[self.urlTimerWindowController showWindow:self];

Any tips greatly appreciated.

Upvotes: 1

Views: 418

Answers (1)

Christopher Pickslay
Christopher Pickslay

Reputation: 17782

The problem with your test is that mockWindowController and urlTimerWindowController are not the same object. And self in your test is not the same as self in the class under test. It doesn't really matter that the nib doesn't load in this case.

You generally can't mock an object when it's instantiated inside the method you want to test. One alternative is to instantiate the object in one method, then pass it to another method that finishes the setup. Then you can test the setup method. For example:

-(void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    self.urlTimerWindowController = [[URLTimerWindowController alloc] init];
    [self setUpTimerWindow:urlTimerWindowController];
}

-(void)setUpTimerWindow:(URLTimerWindowController *)controller {
    [controller showWindow:self];
}

Then, you would test setUpTimerWindow::

-(void)testSetUpTimerWindowShouldShowWindow {
    URLTimerAppDelegate *appDelegate = [[URLTimerAppDelegate alloc] init];

    id mockWindowController = [OCMockObject niceMockForClass:[URLTimerWindowController class]];
    [[mockWindowController expect] showWindow:appDelegate]; // this seems weird. does showWindow really take the app delegate as a parameter?

    [appDelegate setUpTimerWindow:mockWindowController];

    [mockWindowController verify];
    [appDelegate release];
}

Upvotes: 1

Related Questions