使用具有未知数量的方法调用的 OCMock
Posted
技术标签:
【中文标题】使用具有未知数量的方法调用的 OCMock【英文标题】:Using OCMock with Unknown Number of Method Calls 【发布时间】:2013-05-08 17:16:33 【问题描述】:我将 OCMock 与 GHUnit 结合使用,以尝试从 Test-Driven ios Development 重新创建 Graham Lee 的“BrowseOverflow”项目。
我的理解是模拟任何不是您正在测试的当前类的对象。我正在使用我的 Question 类,该类依赖于 Answer 类的某些功能。
Questsion.h
@class Answer;
@interface Question : NSObject
NSMutableSet *answerSet;
@property (retain) NSDate *date;
@property NSInteger score;
@property (copy) NSString *title;
@property (readonly) NSArray *answers;
- (void)addAnswer:(Answer *)answer;
@end
Question.m
#import "Question.h"
#import "Answer.h"
@implementation Question
@synthesize date;
@synthesize score;
@synthesize title;
- (id)init
if ((self = [super init]))
answerSet = [[NSMutableSet alloc] init];
return self;
- (void)addAnswer:(Answer *)answer
[answerSet addObject:answer];
- (NSArray *)answers
return [[answerSet allObjects] sortedArrayUsingSelector:@selector(compare:)];
@end
Answer.h
#import <Foundation/Foundation.h>
@class Person;
@interface Answer : NSObject
@property (readwrite) NSString *text;
@property (readwrite) Person *person;
@property (readwrite) NSInteger score;
@property (readwrite, getter = isAccepted) BOOL accepted;
- (NSComparisonResult)compare:(Answer *)otherAnswer;
@end
Answer.m
#import "Answer.h"
@implementation Answer
@synthesize text;
@synthesize person;
@synthesize score;
@synthesize accepted;
- (NSComparisonResult)compare:(Answer *)otherAnswer
if (accepted && !(otherAnswer.accepted))
return NSOrderedAscending;
else if (!accepted && otherAnswer.accepted)
return NSOrderedDescending;
if (score > otherAnswer.score)
return NSOrderedAscending;
else if (score < otherAnswer.score)
return NSOrderedDescending;
return NSOrderedSame;
@end
我在测试时尝试使用 OCMock 代替 Answer 的实例,但它只在大约 10% 的时间里起作用。
- (void)testHighScoreAnswerBeforeLow
lowScore = [OCMockObject mockForClass:[Answer class]];
[[[lowScore stub] andReturn:OCMOCK_VALUE((NSInteger) 4)] score];
[question addAnswer:lowScore];
highScore = [OCMockObject mockForClass:[Answer class]];
[[[highScore stub] andReturn:OCMOCK_VALUE((NSInteger) -4)] score];
[question addAnswer:highScore];
[[lowScore expect] compare:[OCMArg any]];
NSArray *answers = question.answers;
NSInteger highIndex = [answers indexOfObject:highScore];
NSInteger lowIndex = [answers indexOfObject:lowScore];
GHAssertTrue(highIndex < lowIndex, @"High-scoring index comes first");
[highScore verify];
[lowScore verify];
我认为问题是由 NSSet 如何在内存中存储对象(有点随机)和 OCMock 检查以确保没有调用额外的方法这一事实引起的冲突。我通过将 OCMock 排除在此特定测试中来解决问题,但这似乎是一个糟糕的测试。
- (void)testHighScoreAnswerBeforeLow
lowScore = [[Answer alloc] init];
lowScore.score = -4;
[question addAnswer:lowScore];
highScore = [[Answer alloc] init];
highScore.score = 4;
[question addAnswer:highScore];
NSArray *answers = question.answers;
NSInteger highIndex = [answers indexOfObject:highScore];
NSInteger lowIndex = [answers indexOfObject:lowScore];
GHAssertTrue(highIndex < lowIndex, @"High-scoring index comes first");
当您不知道 OCMock 需要进行多少次比较时,是否可以让 OCMock 与排序算法配合得很好?如果不是,这是使用 OCMock 的缺点还是代码结构不佳?
【问题讨论】:
【参考方案1】:问题是您对比较设定了期望。如果你不在乎它被调用了多少次,你不应该告诉模拟你希望它被调用一次。
如果您不关心在模拟对象上调用了哪些意外方法,则可以使用 nicemock。
您可以使用存根只返回某个值,而不关心它被调用了多少次。
【讨论】:
OCMockito 也有不错的模拟。 有关 stub 和 mock 之间区别的更多信息,请查看 Martin Fowler 的规范文章:martinfowler.com/articles/mocksArentStubs.html 感谢大家的指点!事后看来,这个问题似乎非常基本。 @GrahamLee 你会推荐 OCMockito 而不是 OCMock? 使用任何你喜欢的工具,如果他们能胜任的话 :)以上是关于使用具有未知数量的方法调用的 OCMock的主要内容,如果未能解决你的问题,请参考以下文章