3

in my base mock class:

- (void)tearDown
{
    _mockApplication = nil;
    self.observerMock = nil;
    self.notificationCenterMock = nil;
}

where notificaitonCenterMock is just an id;

Then in my tests I do things like this:

self.notificationCenterMock = [OCMockObject partialMockForObject:[NSNotificationCenter defaultCenter]];
[(NSNotificationCenter *) [self.notificationCenterMock expect]
        removeObserver:self.component
                  name:UIApplicationDidBecomeActiveNotification
                object:nil];

Now.. if I run this code my unit tests will spuriously fail (i.e. only 60 of 370 will run on one run, 70 or 65 the next). Several of my unit tests will fail with the following errors:

OCPartialMockObject[NSNotificationCenter]: expected method was not invoked: removeObserver:    
<VPBCAdComponent-0x17d43e0-384381847.515513: 0x17d43e0> name:@"UIApplicationDidBecomeActiveNotification" object:nil
Unknown.m:0: error: -[VPBCAdComponentTests testCleanUpAfterDisplayingClickthrough_adBrowser_delegateCallback] :       
OCPartialMockObject[NSNotificationCenter]: expected method was not invoked: removeObserver:
<VPBCAdComponent-0x17d43e0-384381847.515513: 0x17d43e0> name:@"UIApplicationDidBecomeActiveNotification" object:nil

The tests will then be Terminated. I can clearly see that partially mocking the notification center causes problems for running the test suite.

The question is, what should I do? It'd be extremely nice to ensure that important things such as observers are set, and regression proof..

Infrid
  • 336
  • 1
  • 3
  • 13

2 Answers2

0

If you can avoid the partial mock in this case, do it. You should be able to use a standard mock or nice mock if you only want to test that observers are added and removed.

And if you can isolate just a few tests that will verify the observers are added and removed, then it shouldn't have such a ripple effect?

id mockCenter = [OCMockObject mockForClass:[NSNotificationCenter class]];
[[mockCenter expect] addObserver:observer options:UIApplicationDidBecomeActiveNotification context:nil];

// method on the Subject Under Test

[mockCenter verify];
Tony Eichelberger
  • 7,044
  • 7
  • 37
  • 46
0

I personaly use local mocks in such cases. A smaller mock scope ensures less interference with other parts of the application. More important in case of NSUserDefaults or other shared objects. The test pattern I use is the same.

- (void)testRegisterNofificaitonTest {
    id ncMock = OCMClassMock([NSNotificationCenter class]);
    OCMStub([ncMock defaultCenter]).andReturn(ncMock);

    UIViewController *sut = [UIViewController new];
    [[ncMock expect] addObserver:sut selector:@selector(doSomething:) name:@"NotificationName" object:nil];

    [sut viewDidLoad]; //assuming viewDidLoad calls [[NSNotificationCenter defaultCenter] addObserver: ...

    [ncMock verify];
    [ncMock stopMocking];
}
Apoc
  • 797
  • 1
  • 10
  • 15