1

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.

bbum
  • 162,346
  • 23
  • 271
  • 359
Lazloman
  • 41
  • 1
  • 3
  • Attempting to test the retain count is pointless. I added some common tags so someone who can answer the specific problem might see this. – bbum Apr 11 '11 at 15:23
  • Yes, testing the retain count seems silly to me as well. I got that from the WhereIsMyMac sample code and unit tests and just left it in. I wanted to try to get things working first and then I'd pare things down from there, but right away, I ran into this issue. – Lazloman Apr 11 '11 at 20:09
  • Where did you get that sample code? Got an URL? I grabbed the first thing I saw in Google and didn't see said code. – bbum Apr 11 '11 at 20:41
  • From here: http://cocoawithlove.com/2009/12/sample-mac-application-with-complete.html – Lazloman Apr 11 '11 at 21:11
  • Thanks -- I left a comment there pointing out that the use of `retainCount` in that code is broken. Unfortunately, I don't know the answer to this specific problem. – bbum Apr 11 '11 at 22:00
  • I'm thinking this sample code is not a very good example of using mock objects. I think I understand the concepts well enough to go my own way. I may post something later for comments. – Lazloman Apr 12 '11 at 02:46

1 Answers1

1

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];
}
Christopher Pickslay
  • 17,523
  • 6
  • 79
  • 92