for (id item in collection)
if (![matchSequence matches:item])
return NO;
return [matchSequence isFinishedWith:collection];
}
代码9,HC_containsInAnyOrder规则中的两个核心方法
我们的需求是,当匹配规则列表全部成功匹配之后就是此次匹配成功的标志。所以需要修改matches:方法中的匹配逻辑,当匹配列表为空则返回YES。
升级方案是继承HCIsCollectionContainingInAnyOrder创建一个新的匹配规则类HCIsCollectionHavingInAnyOrder;重新定义匹配规则HC_hasInAnyOrder;重写调用matches:方法的matches:describingMismatchTo:方法(代码10);更新的核心是定义一个HCMatchingInAnyOrderEx类,按照个性需求定义matches:方法(代码11)。使用这个修改过的匹配规则就可以判断一个Collection是否包含某个几个元素了。
@implementation HCIsCollectionHavingInAnyOrder
- (BOOL)matches:(id)collection describingMismatchTo:(id)
mismatchDescription
{
if (![collection conformsToProtocol:@protocol(NSFastEnumeration)])
{
[super describeMismatchOf:collection to:mismatchDescription];
return NO;
}
HCMatchingInAnyOrderEx *matchSequence =
[[HCMatchingInAnyOrderEx alloc] initWithMatchers:matchers
mismatchDescription:mismatchDescription];
for (id item in collection)
if (![matchSequence matches:item])
return NO;
return [matchSequence isFinishedWith:collection];
}
@end
id HC_hasInAnyOrder(id itemMatch, ...)
{
NSMutableArray *matchers = [NSMutableArray arrayWithObject:HCWrapInMatcher
(itemMatch)];
va_list args;
va_start(args, itemMatch);
itemMatch = va_arg(args, id);
while (itemMatch != nil)
{
[matchers addObject:HCWrapInMatcher(itemMatch)];
itemMatch = va_arg(args, id);
}
va_end(args);
return [HCIsCollectionHavingInAnyOrder isCollectionContainingInAnyOrder:matchers];
}
代码10,HCIsCollectionHavingInAnyOrder实现
(BOOL)matches:(id)item
{
NSUInteger index = 0;
BOOL matched = (0 >= [self.matchers count]);
for (id matcher in self.matchers)
{
if ([matcher matches:item]) {
[self.matchers removeObjectAtIndex:index];
matched = YES;
return YES;
}
++index;
}
return matched;
}
代码11,更新过的matches:方法
(void)testAddConfig
{
[UMNavigationController setViewControllerName:@"ViewControllerA" forURL:@"um://
viewa2"];
NSMutableDictionary *config = [UMNavigationController config];
HC_assertThat([config allKeys],
HC_hasInAnyOrder(HC_equalTo(@"um://viewa2"), nil));
GHAssertEqualStrings(config[@"um://viewa2"], @"ViewControllerA",
@"config set error.");
}
代码12,使用新规则的测试用例
另一个方面,在测试过程中会出现各种逻辑,有时默认规则根本无法覆盖,需要完全自建规则。例如对CGPoint和CGSize的相等匹配,如代码13中对UMView的size和origin方法测试。OCHamcrest的默认规则中根本没有提供任何针对CGPoint和CGSize两个结构体的匹配规则,所以要完成这个测试就需要自己定义针对这两种数据结构的匹配规则。
#pragma mark - UMView
HC_assertThat(NSStringFromCGSize(self.view.size),
HC_equalToSize(self.view.frame.size));
HC_assertThat(NSStringFromCGPoint(self.view.origin),
HC_equalToPoint(CGPointMake(self.view.frame.origin.x, self.
view.frame.origin.y)));
代码13,UMView测试用例片段
自定义匹配规则的详细说明可以参见上一篇《iOS开发中的单元测试(二)》,本文只对开发自定义规则中遇到的问题和需要特殊处理的方面进行解释。
OCHamcrest的匹配规则要求被匹配的必须是一个有强引用的对象,所以当被匹配的是一个struct结构(如CGPoint)需要进行一次转换,如代码14中定义的这个规则扩展——OBJCEXPORT id HCequalToPoint(CGPoint point)。 在CGPoint相等匹配的规则中,需要先把CGPoint转为字符串后传入断言方法,规则会把这个字符串储存起来,并与后续给出的CGPoint进行比较。匹配引擎对传入的需要进行匹配的参数类型没做任何限制,所以规则可以直接传入CGPoint。
原文转自:http://blog.segmentfault.com/gaosboy/1190000000270521