iOS开发中的单元测试:URLManager中的测试用例解析(2)

发表于:2013-11-12来源:sf作者:gaosboy点击数: 标签:单元测试
HC_assertThat(queryUrl.absoluteString, HC_containsString(@p1=v1)); HC_assertThat(queryUrl.absoluteString, HC_containsString(@p2=v2)); } 代码6,URL参数测试用例 匹配规则中的陷阱 由于匹

  HC_assertThat(queryUrl.absoluteString, HC_containsString(@"p1=v1"));

  HC_assertThat(queryUrl.absoluteString, HC_containsString(@"p2=v2"));

  }

  代码6,URL参数测试用例

  匹配规则中的陷阱

  由于匹配规则的粒度较细,所以对于某些运行结果需要考虑到多种情况,否则正常的结果也可能会断言失败。

  例如测试用例期望得到一个空容器(例如:NSArray),而SDK则认为这个容器已经没有存在的必要而释放了他,返回的是一个nil。对removeAllSubviews的测试中,对一个view调用removeAllSubviews方法,期望view.subviews为空。在SDK 6.x甚至SDK 7 DP1之前,都是没问题的,但在SDK 7 DP3中,SDK会把所有清空的容器和对象释放,以回收系统资源。在这种条件下view.subviews返回的就是nil,如果只是做类似HC_empty()这样的匹配,断言会失败,所以在断言之前做一个subviews属性的空判断(代码7)。

  (void)testRemoveAllSubviews

  {

  UIView *subViewA = [[UIView alloc] init];

  UIView *subViewB = [[UIView alloc] init];

  [self.view addSubview:subViewA];

  [self.view addSubview:subViewB];

  HC_assertThat(self.view.subviews, HC_containsInAnyOrder(subViewA, subViewB, nil));

  [self.view removeAllSubviews];

  if (nil != self.view.subviews) {

  HC_assertThat(self.view.subviews, HC_empty());

  }

  }

  代码7,removeAllSubviews用例

  另外,在默认匹配规则中会有一些容易产生歧义的命名,以collection的containsInAnyOrder为例:匹配对象是一个collection对象(也就是遵循NSFastEnumeration协议的对象,NSArray等),给出若干个匹配规则或元素。期待这个规则匹配该对象是否包含给出的若干元素,且不关心顺序。但在实际测试过程中会发现,这个规则要求给出的元素必须是该collection对象的完备集,也就是说要求给出的元素列表和要匹配的容器对象中的元素必须是相等的结合,但允许不关注顺序。

  对UMNavigationController的测试中,需要判断增加一项URL Mapping是否生效,如果使用该匹配规则,就不能单纯判断config是否包含增量的URL,要断言成功必须连同此前config属性初始化写入的值一起考虑,使用一个完整的元素集合进行匹配(代码8)。

  (void)testAddConfig

  {

  [UMNavigationController setViewControllerName:@"ViewControllerA" forURL:@"
um://viewa2"];

  NSMutableDictionary *config = [UMNavigationController config];

  NSLog(@"%@", [config allKeys]);

  HC_assertThat([config allKeys],

  HC_containsInAnyOrder(HC_equalTo(@"um://viewa2"), HC_equalTo(@"
um://viewa"),

  HC_equalTo(@"um://viewb"), nil));

  GHAssertEqualStrings(config[@"um://viewa2"], @"ViewControllerA",

  @"config set error.");

  }

  代码8,AddConfig用例

  自建匹配规则

  上述例子表明匹配规则往往无法恰好满足测试需求,需要对默认规则进行升级。

  升级一个匹配规则,首先阅读OCHamcrest默认规则源码,找到无法满足需求的代码。上述HC_containsInAnyOrder的例子中,个性需求是某个collection是否包含某几个元素(而非完整集合),而默认规则只能匹配完整集合。阅读源码(代码9)可以发现,在maches:describingMismatchTo:函数中,对规则对象的collection属性(要进行匹配的容器对象)进行遍历,并逐个调用matches:方法。matches:方法中针对每个collection属性中的元素遍历匹配规则集合(matchers),并从规则集合(matchers)中移除匹配成功的规则。当给出的规则集合(matchers)全部成功匹配过之后,matchers属性已经为空。若此时对collection属性的遍历继续进行,matches:方法就不会进入匹配逻辑,直接跳出循环返回NO,导致匹配失败。

  (BOOL)matches:(id)item

  {

  NSUInteger index = 0;

  for (id matcher in matchers)

  {

  if ([matcher matches:item])

  {

  [matchers removeObjectAtIndex:index];

  return YES;

  }

  ++index;

  }

  [[mismatchDescription appendText:@"not matched: "] appendDescriptionOf:item];

  return NO;

  }

  - (BOOL)matches:(id)collection describingMismatchTo:(id)
mismatchDescription

  {

  if (![collection conformsToProtocol:@protocol(NSFastEnumeration)])

  {

  [super describeMismatchOf:collection to:mismatchDescription];

  return NO;

  }

  HCMatchingInAnyOrder *matchSequence =

  [[HCMatchingInAnyOrder alloc] initWithMatchers:matchers

  mismatchDescription:mismatchDescription];

原文转自:http://blog.segmentfault.com/gaosboy/1190000000270521