Infrid
Infrid

Reputation: 336

Why does OCMock cause nsnotificaiton center to have EXC_BAD_ACCESS when using mockObserver

I setup mock observers like this:

id quartileObserverMock = [OCMockObject observerMock];
[[NSNotificationCenter defaultCenter] addMockObserver:quartileObserverMock
                                                 name:kVPAdPlayerDidReachQuartileNotification
                                               object:self.adPlayer];

[[quartileObserverMock expect]
                       notificationWithName:kVPAdPlayerDidReachQuartileNotification
                                     object:self.adPlayer
                                   userInfo:@{@"quartile" : @(VPAdPlayerFirstQuartile), @"trackingEvent" : VPCreativeTrackingEventFirstQuartile}];

my unit tests run; but I get spurious EXC_BAD_ACCESS errors when the notificaiton is posted.

i.e.

[[NSNotificationCenter defaultCenter]
                           postNotificationName:kVPAdPlayerDidReachQuartileNotification
                                         object:self.adPlayer
                                       userInfo:@{@"quartile" : @(quartile), @"trackingEvent" : trackingEvent}];

When I comment out the observermock code my tests run fine every single time.

When I put the code back in, I get spurious crashes on postNotiicaitonName:object:userInfo, maybe once every 2.5 times.

Anyone got any ideas?

Upvotes: 2

Views: 1351

Answers (2)

Drew H
Drew H

Reputation: 1292

There are a couple of reasons why this could be happening (I know, because I just solved both of them them in my own code today)

1) A mock observer from a previous test was not removed

2) An non-mock instance object from a previous test is observing for the same notification, but that object has since become obsolete. In my case, an instance object from my setUp method was listening to the notification, but when it was dealloced, it did not remove itself from the NSNotificationCenter's observers list.

In both cases the solution is to use

  [[NSNotificationCenter defaultCenter] removeObserver:name:object:]

Depending on the scope: 1) in the dealloc of all classes that observe NSNotificationCenter, 2) in the tearDown method, or 3) at the end of the test case (as @PrasadDevadiga mentioned)

Upvotes: 1

Prasad Devadiga
Prasad Devadiga

Reputation: 2589

Refer the following sample code, this might help you. It worked for me

- (void)test__postNotificationwithName__withUserInfo
{
     id observerMock  = [OCMockObject observerMock];
     [[NSNotificationCenter defaultCenter] addMockObserver:observerMock name:@"NewNotification" object:nil];

     NSDictionary *userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:@"2",@"2", nil];
     [[observerMock expect] notificationWithName:@"NewNotification" object:[OCMArg any] userInfo:userInfo];

     NotificationClass *sut = [[NotificationClass alloc] init];
     [sut postNotificationwithName:@"NewNotification" userInfo:userInfo];

     [[NSNotificationCenter defaultCenter] removeObserver:observerMock];
     [observerMock verify];
}

and my posting notification method

- (void)postNotificationwithName:(NSString *)notifName userInfo:(NSDictionary *)userInfo
{
     [[NSNotificationCenter defaultCenter] postNotificationName:notifName object:self userInfo:userInfo];
}

Please note:

  1. observerMock always raise an exception when an unexpected notification is received.
  2. Remove the mocked observer from the NSNotificationCenter at the end of the test case.

Upvotes: 8

Related Questions