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