For a game I'm developing, I have several model classes that trigger notifications when their state changes. Then, the view subscribes to those notifications and can react on them.
I'm doing my unit tests for the model with OCUnit, and want to assert that the expected notifications were posted. For that, I'm doing something like this:
- (void)testSomething {
[[NSNotificationCenter defaultCenter] addObserver:notifications selector:@selector(addObject:) name:kNotificationMoved object:board];
Board *board = [[Board alloc] init];
Tile *tile = [Tile newTile];
[board addTile:tile];
[board move:tile];
STAssertEquals((NSUInteger)1, [notifications count], nil);
// Assert the contents of the userInfo as well here
[board release];
}
The idea is that the NSNotificationCenter
will add the notifications to the NSMutableArray
by calling its addObject:
method.
When I run it, however, I see that addObject:
is being sent to some other object (not my NSMutableArray
) causing OCUnit to stop working. However, if I comment out some code (such as the release
calls, or add a new unit test) everything starts working as expected.
I'm assuming this has to o with a timing issue, or NSNotificationCenter
relying on the run loop in some way.
Is there any recommendation to test this? I know I could add a setter in Board
and inject my own NSNotificationCenter
, but I'm looking for a quicker way to do it (maybe some trick on how to replace the NSNotificationCenter
dynamically).
Found the problem. When testing notifications you need to remove the observer after you have tested it. Working code:
- (void)testSomething {
[[NSNotificationCenter defaultCenter] addObserver:notifications selector:@selector(addObject:) name:kNotificationMoved object:board];
Board *board = [[Board alloc] init];
Tile *tile = [Tile newTile];
[board addTile:tile];
[board move:tile];
STAssertEquals((NSUInteger)1, [notifications count], nil);
// Assert the contents of the userInfo as well here
[board release];
[[NSNotificationCenter defaultCenter] removeObserver:notifications name:kNotificationMoved object:board];
}
If you fail to remove the observer, after a test runs and some local variables are released, the notification center will try to notify those old objects when running any subsequent test that triggers the same notification.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With