代码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中定义的这个规则扩展——OBJC_EXPORT id HC_equalToPoint(CGPoint point)。 在CGPoint相等匹配的规则中,需要先把CGPoint转为字符串后传入断言方法,规则会把这个字符串储存起来,并与后续给出的CGPoint进行比较。匹配引擎对传入的需要进行匹配的参数类型没做任何限制,所以规则可以直接传入CGPoint。
  开发自定义规则一般建议同时定义SHORTHAND,即使当前单元测试中不会用到(例如本文中的测试),但这个规则被其他复用的时候,可能会用到SHORTHAND命名。
  #import
  OBJC_EXPORT id HC_equalToPoint(CGPoint point);
  #ifdef HC_SHORTHAND
  #define equalToPoint HC_equalToPoint
  #endif
  @interface HCIsEqualToPoint : HCBaseMatcher
  + (id)equalToPoint:(CGPoint)point;
  - (id)initWithPoint:(CGPoint)point;
  @property (nonatomic, assign)       CGFloat     x;
  @property (nonatomic, assign)       CGFloat     y;
  @end
  代码14,扩展匹配规则HC_equalToPoint定义
  在匹配规则的过程中,有一个点需要特别注意,即对匹配对象类型和完整性的判断。往往开发者把注意力都放在对对象值的匹配上,而忽略了类型和完整性这类判断,终导致整个用例运行失败,但无法准确定位出错的位置。上面提到的对subviews是否为空的判断也是这样的一个例子。所以在自定义的匹配规则中需要考虑到这方面的问题,如代码15的matches:方法中,先要对传入的泛型对象item校验是否为字符串,后再转化为CGPoint对象,并进行相应比对。示例中给出的是一种较简单的情况,在更复杂的情况下,除了对泛型对象的类进行校验,还要校验其是否响应某方法,属性类型,空判断,等。

 

#import "HCIsEqualToPoint.h"
#import
id  HC_equalToPoint(CGPoint point)
{
return [HCIsEqualToPoint equalToPoint:point];
}
@implementation HCIsEqualToPoint
+ (id)equalToPoint:(CGPoint)point
{
return [[self alloc] initWithPoint:point];
}
- (id)initWithPoint:(CGPoint)point
{
self = [super init];
if (self) {
self.x = point.x;
self.y = point.y;
}
return self;
}
- (BOOL)matches:(id)item
{
if (! [item isKindOfClass:[NSString class]]) {
return NO;
}
CGPoint point = CGPointFromString((NSString *)item);
return (point.x == self.x && point.y == self.y);
}
- (void)describeTo:(id)description
{
[description appendText:@"Point not equaled."];
}
@end

  代码15,扩展匹配规则HC_equalToPoint实现
  一个操作多个测试方法
  以上提到的几个例子中所测试的都是非常简单的操作,所以一个测试方法覆盖了一个或多个操作,但对于较复杂的操作,往往需要多个测试方法,循序渐进的断言。例如测试通过URL生成UMViewController的用例,生成一个UMViewController实例由简单到复杂可以有三种简单方式:简单的URL生成,带参数的URL生成和带Query字典的URL生成,此外还有URL参数和Query字典共用的方式。所以对于这个操作至少需要使用4个测试方法(代码16)分别进行测试。