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

发表于:2013-11-12来源:sf作者:gaosboy点击数: 标签:单元测试
iOS开发中的单元测试:URLManager中的测试用例解析 URLManager是一个基于UINavigationController和UIViewController,以URL Scheme为设计基础的导航控件,目的是实现ViewController的松耦合,不依赖。

  URLManager是一个基于UINavigationController和UIViewController,以URL Scheme为设计基础的导航控件,目的是实现ViewController的松耦合,不依赖。

  准备框架,定义基类

  首先按照之前的两篇文章介绍的方法导入单元测试框架和匹配引擎框架,建立好测试Target,并配置编译选项。

  定义测试用例基类:UMTestCase(代码1),其他用例全部继承自UMTestCase。

  #import @interface UMTestCase : GHTestCase @end

  代码1,UMTestCase,用例基类

  构建用例

  URLManager工具类(UMTools)测试用例(UMToolsTestCase)。UMTools中扩展了NSURL,NSString和UIView,方法涉及到给URL添加QueryString和从QueryString中读取参数,对字符串做子串判断,进行URL的编码和解码,对UIView的x,y,width和height的直接读写等。需要在用例中定义测试过程中会使用到属性(代码2), 并在setUpClass中初始化他们(代码3)。

  代码2,定义属性

  // 普通字符串,带有字母和数字

  @property (strong, nonatomic) NSString *string;

  // 普通字符串,仅带有字母

  @property (strong, nonatomic) NSString *stringWithoutNumber;

  // 将被做URLEncode的字符串,含有特殊字符和汉字

  @property (strong, nonatomic) NSString *toBeEncode;

  // 把 toBeEncode 编码后的串

  @property (strong, nonatomic) NSString *encoded;

  // 普通的URL,带有QueryString

  @property (strong, nonatomic) NSURL *url;

  // 去掉上边一个URL的QueryString

  @property (strong, nonatomic) NSURL *noQueryUrl;

  // 一个普通的UIView

  @property (strong, nonatomic) UIView *view;

  (void)setUpClass

  {

  self.string = @"NSString For Test with a number 8848.";

  self.stringWithoutNumber = @"NSString For Test.";

  self.toBeEncode = @"~!@#$%^&*()_+=-[]{}:;\"'<>.,/?123qwe汉字";

  self.encoded = @"%7E%21%40%23%24%25%5E%26%2A%28%29_%2B%3D-%5B%5D%

  7B%7D%3A%3B%22%27%3C%3E.%2C%2F%3F123qwe%E6%B1%89%E5%AD%97";

  self.url = [NSURL URLWithString:@"http://example.com

  /patha/pathb/?p2=v2&p1=v1"];

  self.noQueryUrl = [NSURL URLWithString:@"http://example.com

  /patha/pathb/"];

  self.view = [[UIView alloc] initWithFrame:CGRectMake(10.0f,

  10.0f, 100.0f, 100.f)];

  }

  代码3,初始化属性

  使用单元测试框架中的断言处理简单用例

  单元测试是白盒测试,要做到路径覆盖(代码4)。 对“ContainsString”的测试进行正向和反向两种情况(即YES和NO两种返回结果)。

  #pragma mark - UMString

  - (void)testUMStringContainsString

  {

  NSString *p = @"For";

  NSString *np = @"BAD";

  GHAssertTrue([self.string containsString:p],

  @"\"%@\" should contains \"%@\".",

  self.string, p);

  GHAssertFalse([self.string containsString:np],

  @"\"%@\" should not contain \"%@\".",

  self.string, p);

  代码4,字符串测试用例

  同时单元测试又要对功能负责,因此在路径覆盖之外还要尽量照顾到完整的功能。例如,对URLEncode的测试(代码5),要对尽量全面的特殊字符进行测试,而不是从源码实现中取出枚举的字符。

  (void)testUrlencode

  {

  GHAssertEqualStrings([self.toBeEncode urlencode], self.encoded,

  @"URLEncode Error.",

  self.toBeEncode, self.encoded);

  GHAssertEqualStrings([self.encoded urldecode], self.toBeEncode,

  @"URLDecode Error.",

  self.encoded, self.toBeEncode);

  }

  代码5,URLEncode测试用例

  在进行这个测试之前,urlencode的实现忽视了对“~”的编码,正是由于单元测试用例所取的特殊字符是单独列举,并非从实现枚举中获取,检查出了这个错误。

  引入匹配引擎,使用匹配引擎默认规则

  前文提到过匹配引擎可以使测试用例中的断言更加丰富,URLManager的用例中也使用了匹配引擎:OCHamcrest。

  在此前的介绍中提到,引入OCHamcrest可以通过定义 HC_SHORTHAND 来开启匹配引擎的简写模式。因为开启简写模式后匹配规则中的“containsString”规则和上述例子(代码5)中的“containsString:”方法命名冲突,导致测试程序无法正常运行,所以这个工程直接使用了类似 HC_asserTaht 这样带有HC前缀的完整命名。

  我建议使用匹配引擎的开发者谨慎开启简写功能,OCHamcrest的匹配规则简写通常是很常见的单词,非常容易与工程中的类定义或方法定义重名。即使当下没有规则和方法名发生冲突,随着工程代码量的增加,一旦出现命名冲突的情况,重构的成本将非常高。

  匹配引擎可以提供更丰富的断言,最简单的例如,URLManager的UMURL扩展支持向一个URL上添加参数,对这个方法测试断言就用到了匹配某个字符串是否包含某子串的规则(代码6)。

  #pragma mark - UMURL

  - (void)testAddParams

  {

  NSURL *queryUrl = [self.noQueryUrl addParams:@{@"p1":@"v1",@"p2":@"v2"}];

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