热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[S01E02]iOS单元测试

[S01E02]iOS单元测试-what:什么是单元测试how:如何进行单元测试why:为什么要做单元测试一、什么是单元测试1、单元测试单元可以简单地理解为一个方法,

what:什么是单元测试 how: 如何进行单元测试 why: 为什么要做单元测试

一、什么是单元测试

1、单元测试

单元可以简单地理解为一个方法,那么单元测试就是针对方法的测试

2、单元测试在测试中所处的位置

一般来讲,小型测试用来保障代码质量,中、大型测试用来保障产品质量。

分类测试
小型测试这里一般值得是单元测试
中型测试逻辑层测试
大型测试UI测试/接口测试

测试金字塔从下往上依赖于来越多,但是我们对整个产品质量的信心是越来越强的。我们需要为单元测试提供mock环境。 一般的,单元测试不依赖任何外部环境、网络环境、数据库环境。 单元测试是整个测试金字塔的基石。在整个测试中占据非常重要的位置。

参考:《Google软件测试之道》

二、如何进行单元测试

2.1 如何给项目新增单元测试Scheme

如果我们在创建项目的时候没有勾选include Tests,那我们就需要给项目新增测试的Scheme

2.2 新增一个测试用例

在新建的DemoTests下面的DemoTests.m中新增一条测试用例,测试用例必须是实例方法,返回值为void并且以test开头

- (void)testExample {
    // This is an example of a functional test case.
    // Use XCTAssert and related functions to verify your tests produce the correct results.
}

2.3 常用断言

    XCTFail(@"Fail");
    XCTAssertNil(@"not nil string", @"string must be nil");
    XCTAssertNotNil(@"not nil string", @"string can not be nil");
    XCTAssert((2 > 2), @"expression must be true");
    XCTAssertTrue(1, @"Can not be zero");
    XCTAssertFalse((2 <2), @"expression must be false");
    XCTAssertEqualObjects(@"1", @"1", @"[a1 isEqual:a2] should return YES");
    XCTAssertNotEqualObjects(@"1", @"2", @"[a1 isEqual:a2] should return NO");
    XCTAssertEqual(1, 2, @"a1 = a2 shoud be true"); 
    XCTAssertEqual(str1, str2, @"a1 and a2 should point to the same object"); 

2.4 测试文件中各个函数执行的顺序

控制台输出的结果如下

2021-07-08 14:29:10.782883+0800 Demo[19597:31722127] ? +setUp
2021-07-08 14:29:10.784474+0800 Demo[19597:31722127] ? -setUp
2021-07-08 14:29:10.784667+0800 Demo[19597:31722127] ? testExample1
2021-07-08 14:29:10.784857+0800 Demo[19597:31722127] ? -tearDown
2021-07-08 14:29:10.785971+0800 Demo[19597:31722127] ? -setUp
2021-07-08 14:29:10.786121+0800 Demo[19597:31722127] ? testExample2
2021-07-08 14:29:10.786270+0800 Demo[19597:31722127] ? -tearDown
2021-07-08 14:29:10.787399+0800 Demo[19597:31722127] ? -setUp
2021-07-08 14:29:10.787548+0800 Demo[19597:31722127] ? testExample3
2021-07-08 14:29:10.787700+0800 Demo[19597:31722127] ? -tearDown
2021-07-08 14:29:10.788271+0800 Demo[19597:31722127] ? +tearDown

值得注意的是,testExample1、testExample2、testExample3的执行并没有一定的顺序。

2.2 如何在Xcode中查看单元测试覆盖率

单元测试的覆盖率问题默认是关闭的,需要在Xcode中打开

三、为什么要做单元测试
  • 检查代码逻辑
  • 验证边界条件
  • 保障重构的顺利进行

3.1 检查代码逻辑

单元测试最基本的功能就是验证我们函数的逻辑是否符合预期。

3.2 验证边界条件

点赞数显示字符串转换,例如本条视频的真实点赞数字是23848999,我们显示2384.8

/// 将点赞的数量转换成字符串
/// @param count 点赞数量
/// @discussion 数字大于等于1万时,保留一位小数点
/// @discussion 数字低于1万时,展示真实数字
- (NSString *)descForLikeCount:(NSInteger)count{
    NSString *desc = nil;
    if (count >= 10000) {
        desc = [NSString stringWithFormat:@"%.1f万", (count / 10000.f)];
    }else{
        desc = [NSString stringWithFormat:@"%ld", count];
    }
    return desc;
}

上面的函数乍一看并没有什么问题,但是当我们输入99999的时候函数的返回值却是10.0万并不符合我们的预期。类似这样的错误甚至在代码评审(Code Review)中也很难被发现。

3.3 保障重构的顺利进行

定义方向枚举

typedef enum{

    DIREDRTION_UNKNOW = -1, // 未知方向
    DIREDRTION_N = 0, // 北
    DIREDRTION_E = 1, // 东
    DIREDRTION_S = 2, // 南
    DIREDRTION_W = 3 // 西

}DIREDRTION;

重构前的函数:

- (DIREDRTION)turn:(NSString *)cmd curDirection:(DIREDRTION)curDirection{
    if ([cmd isEqualToString:@"L"]){
        if (curDirection == DIREDRTION_N) {
            return DIREDRTION_W;
        }
        if (curDirection == DIREDRTION_W) {
            return DIREDRTION_S;
        }
        if (curDirection == DIREDRTION_S) {
            return DIREDRTION_E;
        }
        if (curDirection == DIREDRTION_E) {
            return DIREDRTION_N;
        }
    }else if ([cmd isEqualToString:@"R"]){
        if (curDirection == DIREDRTION_N) {
            return DIREDRTION_E;
        }
        if (curDirection == DIREDRTION_W) {
            return DIREDRTION_N;
        }
        if (curDirection == DIREDRTION_S) {
            return DIREDRTION_W;
        }
        if (curDirection == DIREDRTION_E) {
            return DIREDRTION_S;
        }
    }
    return  DIREDRTION_UNKNOW;
}

这时候我们需要一些单元测试作为保障

随着工作的深入,我们发现了一个规律

左转:最终方向 = (当前方向 + 3) % 4

右转:最终方向 = (当前方向 + 5) % 4

重构后的函数:

- (DIREDRTION)turn:(NSString *)cmd curDirection:(DIREDRTION)curDirection{
    if ([cmd isEqualToString:@"L"]) {
        DIREDRTION direction = (curDirection + 3) % 4;
        return direction;
    }
    if ([cmd isEqualToString:@"R"]) {
        DIREDRTION direction = (curDirection + 5) % 4;
        return direction;
    }
    return  DIREDRTION_UNKNOW;
}

重构完成之后,运行单元测试。依旧全部通过。证明此次重构并没有引入新的问题。

到目前为止,我想你已经单元测试坚定的拥护者了。但是我们之前说过,单元测试并不依赖网络环境、系统时间、数据库,只是单纯的对函数功能的测试,要想更好的进行单元测试,你还必须掌握mock,请继续观看下一章节《OCMock的使用》。


推荐阅读
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • Myappcrashedandthecodeisthefollowing:我的应用程序崩溃,代码如下:elseif(){CGDetailVie ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • 本文整理了Java中org.apache.hadoop.hive.ql.plan.ExprNodeColumnDesc.getTypeInfo()方法的一些代码示例,展 ... [详细]
  • 通过手机浏览器调用客户端QQ
    php教程|php手册thinkphp代码,代码示例,代码参考,php短信,数据库备份代码,令牌验证,去除代码中的空白和注释调用QQ客户端php教程-php手册可调用iosandr ... [详细]
  • 在真实开发中,因为需求是不断变化的,说不定什么时候就需要往模型里添加新的字段,添加新的模型,甚至是大规模的重构; ... [详细]
  • 表达式树摘录(1)
    本文主要讲述ConstantExpression介绍表示具有常量值的表达式。ParameterExpression介绍表示命名的参数表达式。UnaryExpression介绍表示包 ... [详细]
  • 代码如下:Stringpathrequest.getContextPath();StringbasePathrequest.getScheme():request ... [详细]
  • 20189216 2018-2019-2 《密码与安全新技术专题》第二次作业
    201892162018-2019-2《密码与安全新技术专题》第二次作业课程:《密码与安全新技术专题》班级:1892班姓名:鲍政李学号:20189216上课教师:谢四江上课日期: ... [详细]
author-avatar
色花君子fds_181
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有