对于我正在开发的游戏,我有几个模型类,当它们的状态改变时会触发通知。然后,视图订阅这些通知,并可以对它们做出反应。
我正在使用OCUnit对模型进行单元测试,并希望断言预期的通知已经发布。为此,我这样做:
- (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将通过调用其addObject:方法将通知添加到NSMutableArray。
然而,当我运行它时,我看到addObject:被发送到其他对象(而不是我的NSMutableArray),导致OCUnit停止工作。但是,如果我注释掉一些代码(比如release调用,或者添加一个新的单元测试),一切都会按预期开始工作。
我假设这与计时问题有关,或者NSNotificationCenter在某种程度上依赖于run循环。
有没有什么建议来测试这个?我知道我可以在Board中添加一个设置器并注入我自己的NSNotificationCenter,但我正在寻找一种更快的方法(也许是关于如何动态替换NSNotificationCenter的一些技巧)。
发布于 2009-06-11 14:07:51
找到了问题所在。在测试通知时,您需要在测试之后删除观察者。工作代码:
- (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];
}如果您未能移除观察者,则在测试运行并释放某些局部变量后,通知中心将在运行任何触发相同通知的后续测试时尝试通知这些旧对象。
发布于 2009-06-09 15:06:54
没有计时问题或运行循环相关的问题,因为代码中的所有内容都是非并发的,应该立即执行。如果您使用NSNotificationQueue,则NSNotificationCenter仅会延迟通知传递。
我认为你发布的代码片段中的一切都是正确的。可能是可变数组'notifications‘有问题。你是否正确地初始化和保留了它?尝试手动添加一些对象,而不是使用通知技巧。
发布于 2009-06-11 08:53:32
如果你怀疑你的测试有时间问题,你可以考虑把你自己的通知机制注入到你的board对象中(它可能只是现有苹果版本的一个包装器)。
这就是:
Board *board = [[Board alloc] initWithNotifier: someOtherNotifierConformingToAProtocol];假设您的board对象发布了一些通知-您将在该代码中使用注入的通知程序:
-(void) someBoardMethod {
// ....
// Send your notification indirectly through your object
[myNotifier pushUpdateNotification: myAttribute];
}在您的测试中-您现在有了一个可用于测试的间接层,因此您可以实现符合您的AProtocol的测试类-并且可能会计入pushUpdateNotification:调用。在您的实际代码中,您封装了可能已经在Board中执行通知的代码。
当然,这是一个典型的MockObjects有用的例子--还有一个OCMock,它可以让你在不需要测试类进行计数的情况下做到这一点(参见:http://www.mulle-kybernetik.com/software/OCMock/)
您的测试可能会有类似以下内容的行:
[[myMockNotifer expect] pushUpdateNotification: someAttribute]; 或者,您可以考虑使用委托而不是通知。这里有一组很好的正反两面幻灯片:http://www.slideshare.net/360conferences/nsnotificationcenter-vs-appdelegate。
https://stackoverflow.com/questions/970333
复制相似问题