开发人员必备的技能——单元测试

提及软件测试四个字,想必你们脑海中浮现的有集成测试、系统测试、黑盒测试、白盒测试等,可能就是没想到会有单元测试。 对于大学是学习软件工程专业出身的同窗来讲可能会听过这四个字,对工做好几年的职场老鸟可能也听过可是没实际用过居多。绝大多数的开发人员都是忙于把手头的工做开发好,并不会把单元测试归入工做范畴,他们会说,我连功能开发都忙不过来了,哪有时间去作单元测试,何况还要写测试代码,那不是重复写一篇代码功能吗?但,单元测试真的不值得花时间去作吗,那是由于可能你并不清楚单元测试的投入产出比有多高,下面就简单介绍单元测试到底能给开发人员带来多少好处。html

  • 什么是单元测试
  • 为何要作单元测试
  • 不写单元测试借口
  • 主流框架 JUnit 和 TestNG
  • Android 中的单元测试
  • 小结

什么是单元测试

单元测试本质上也是代码,与普通代码的区别在于它是验证代码正确性的代码。可简单作个定义:单元测试是开发人员编写的、用于检测在特定条件下目标代码正确性的代码。前端

软件开发天生就具备复杂性,没人敢打包票说本身写的代码一点问题都没有,或者不经测试就能保证代码正确运行,可能你在这个执行路径下可以执行,却不知还有其余路径,有一一去验证过吗,所以,要保证程序的正确性就必需要对咱们代码进行严格测试。java

举个简单例子:好比有个计算类,里面有个 add 方法,操做就是两个数进行相加。android

public class Calculator {
    public int add(int one, int another) {
        //只是简单的两个数相加
        return one + another;
    }
}

常规作法:假如你写好了这个方法,你想进行验证 add 方法的正确性,须要写个使用 add 方法的 main 函数,首先实例化 Calculator 类,而后调用 add 方法并传入两个参数,好比 1 和 2。而后你运行这个工程,看得出结果是否为 3 ,若是是 3 ,则代表我这个方法写的没有错误,可能就不测试了,就继续开发后续的功能,若是不是 3 ,则返回去看看代码中哪里出错了,从新进行调试,甚至有时候肉眼还看不出代码哪里出错,此时就引入断点去查看,在此期间,很大一部分时间就花在断点、调试、运行上。数据库

单元测试作法:首先会利用 JUnit 测试框架(至于这个框架后面介绍)写一段测试代码,以下:编程

public class CalculatorTest {
    public void testAdd() throws Exception {
        Calculator calculator = new Calculator();
        int sum = calculator.add(1, 2);
        Assert.assertEquals(3, sum);
    }
}

这里的 CalculatorTest 是 Calculator 对应的测试类,这里的 testAdd 对应着 add 的测试方法,进行测试通常分为三步骤:数组

  • setup。通常是 new 出你要测试的那个类,好比: Calculator calculator = new Calculator();
  • 执行操做。通常是调用你要测试的那个方法,得到运行结果: int sum = calculator.add(1, 2);
  • 验证结果。验证获得的结果跟预期中是同样的: Assert.assertEquals(3, sum);

看到 Assert 这个关键词了吗,这里能够理解为断言或者指望值,根据入参的值,指望有个什么值输出,而不是靠肉眼去验证是否是本身想要的值,是直接经过判断值是否相等性来验证会具备更客观性。性能优化

以上介绍的只是单元测试一点点,那它能给咱们带来哪些更多好处呢?数据结构

为何要作单元测试

一般咱们在作任何工做会先考虑它的回报,编写代码更是如此。若是单元测试的做用不大,没有人会愿意再写一堆无用的代码,那么单元测试到底可以给咱们带来什么优势呢?以下:多线程

  • 便于后期重构。单元测试能够为代码的重构提供保障,只要重构代码以后单元测试所有运行经过,那么在很大程度上表示此次重构没有引入新的BUG,固然这是创建在完整、有效的单元测试覆盖率的基础上。
  • 优化设计。编写单元测试将使用户从调用者的角度观察、思考,特别是使用TDD驱动开发的开发方式,会让使用者把程序设计成易于调用和可测试,而且解除软件中的耦合。
  • 文档记录。单元测试就是一种无价的文档,它是展现函数或类如何使用的最佳文档,这份文档是可编译、可运行的、而且它保持最新,永远与代码同步。
  • 具备回归性。自动化的单元测试避免了代码出现回归,编写完成以后,能够随时随地地快速运行测试,而不是将代码部署到设备以后,而后再手动地覆盖各类执行路径,这样的行为效率低下,浪费时间。

等等,讲了这么多优势,无非就是良好的接口设计、正确性、可回归、可测试、完善的调用文档、高内聚、低耦合,这些优势已经足以让咱们对单元测试重视起来了,可是我的以为还有更重要的缘由。

  • 首先,带来自信。在接手一个新的项目,或者说是参与一个新的项目开发时,每每这种状况是你半途参加进去的,你须要对已有的代码结构进行解读和理解,对于业务的理解,对于代码个中各个模块关系的理解。若是一开始就理财出错,极可能修改后的代码会引发更多的BUG出现,到那时候又须要修复更多的BUG,改了一个地方,颇有可能会莫名其妙地影响另一个地方,这种现象是很常见的。还有一种状况,假设你修改的功能没问题,可是须要去测试验证,在测试的时候就须要考虑这个功能点它原有的测试路径有哪些,又须要一一去验证功能路径,以证实本次修改对于已存在的功能点不形成影响。这其中就存在着很大的时间成本,致使效率不高。那是否存在着这么一种方式,我须要修改我想改动的地方,不须要关心修改完以后它所形成的影响,也不须要关心它的测试回归性,有,此时就是单元测试登场的时候。写单元测试代码,可让我本身写的代码足够自信,它是经得起考验的。
  • 其次,更快反馈。对于有必定编程经验的开发人员来讲,当他拿到一个新需求的时候,首先想到的不是动手 Coding ,而是会先想一想代码的结构,有些类,数据结构该是如何,而后才开始敲代码。若是没有单元测试,通常流程基本是这个模块功能所有写完才开始测试,好比利用 MVP 架构的功能。通常都是开始 Model 模块,而后完善 Presenter 模块,最后写 View 模块,等这几个模块都写完了,再把 APP 跑起来,验证本身写的功能模块是否符合需求,没有符合则继续回去修改代码,这中间须要花费很长的时间才能知道当下本身写的代码是否符合要求,是否正确。那有没有一种即时反馈的方式呢,有,写单元测试便可,当你写完一个函数,立刻就匹配一个单元测试函数,这样即写即测的方式能够保证你当场写的代码立刻进行修改,测试经过一个,就表示完成一个小的功能点,最后,把函数组装起来,就是咱们想要大的功能点。
  • 最后,节约时间。对于 Android 开发来讲,一遍一遍的运行 APP ,而后执行相应的用户操做,看界面是否正确的显示,经过这种方式来测试功能,实际上是很是浪费时间,并且效率不高,而用单元测试,能够几乎不用打开 APP 来执行,固然有些须要一些资源文件的是须要 APP 运行条件,绝大部分的功能在单元测试阶段就能验证完毕,那么速度就相对快不少。此外,单元测试还能帮忙减小 BUG ,从而减小调试 BUG 的时间,一些低级犯的错误在单元测试阶段就能避免掉。

不写单元测试借口

不少开发人员不写单元测试,最重要的一个缘由是他们并不知道单元测试可以带来什么好处,甚至根本不了解单元测试这个词,那天然就像平行线般与之毫无交集。还有一个比较重要的缘由是一些开发人员的编程思想还处在一个相对初级的阶段,开发软件只管实现功能,什么高内聚、低耦合、重构、设计、可测试等认为太过专业,对于这些名词以及意义还不了解,这天然不会考虑使用了。还有一些非思想层面的理由,以下:

  • 单元测试太花时间了。软件开发工做那么忙,代码都写不完哪有时间写单元测试。这多是开发人员用的最多的借口,从某些方面来讲,这不能算借口,由于不少开发人员确实在工做上投入的时间特别多。但真的是这样的吗,你有没有想过,致使加班的缘由也许就是花了太多时间在手动测试、调试程序上:或许你没有考虑到灵活性与设计,使得在需求发生变动时你须要花不少时间在复杂的代码堆中完成特定的功能,而这些修改又可能引入新的 BUG ,又将致使你须要进行耗时的手动测试、调试等等,如此反复,代码将变得愈来愈乱,愈来愈难以维护,最终致使无休止的加班。
  • 测试不是个人工做。测试确实不是开发人员的工做,但单元测试确实是开发人员的工做,测试包含不少种,而只有单元测试是开发人员的工做范畴。开发人员为应用编写代码,那么天然须要保证代码的正确性,而单元测试正是这种保证代码正确性的白盒测试,也就是在了解代码内部结构逻辑的状况下进行有目的的测试,既然说到了解代码,那么开发者天然是最权威的人。所以,编写单元测试而且为测试人员提交正确的代码进行其余测试是开发人员的职责所在。
  • 代码都编译经过了,还测什么。通常来讲,这是一个不会放在嘴上但可能藏在内心的借口。代码编译经过只能说你写的代码符合语法要求,并不表明能保证正确性。
  • 代码原来就没有单元测试,而且难以测试。这个问题基本是接受和维护别人开发的代码,而原来的代码自己就没有单元测试了,再加入若是代码的耦合性较高,那么就更难觉得这些代码写单元测试。此时正是你了解代码时候,首先为可以测试的部分添加单元测试,保证这些可测试的部分不会被污染,而后在对代码有足够的了解以后再对代码进行重构,下降代码的耦合性,而且慢慢补充测试用例,使得代码的耦合性、可测试性慢慢创建起来。

主流框架 JUnit 和 TestNG

JUnit 是一个 Java 语言的单元测试框架,它是 xUnit 单元测试架构体系的一个实例,用于编写和运行可重复的测试。它包括如下特性:

  • 用于测试指望结果的断言(Assertion)
  • 用于共享共同测试数据的测试工具
  • 用于方便的组织和运行测试的测试套件
  • 图形和文本的测试运行器

TestNG 是一个测试框架,其灵感来自 JUnitNUnit ,但引入了一些新的功能,使其功能更强大,使用更方便。TestNG 消除了大部分的旧框架的限制,使开发人员可以编写更加灵活和强大的测试。 由于它在很大程度上借鉴了Java注解( JDK5.0 引入的)来定义测试,它也能够显示如何使用这个新功能在真实的Java语言生产环境中。

特色以下:

  • 注解
  • TestNG 使用 Java 和面向对象的功能
  • 支持综合类测试(例如,默认状况下,不用建立一个新的测试每一个测试方法的类的实例)
  • 独立的编译时测试代码和运行时配置/数据信息
  • 灵活的运行时配置
  • 主要介绍“测试组”。当编译测试,只要要求 TestNG 运行全部的“前端”的测试,或“快”,“慢”,“数据库”等
  • 支持依赖测试方法,并行测试,负载测试,局部故障
  • 灵活的插件 API
  • 支持多线程测试

Android 中的单元测试

由于 JUnit 测试框架是基于 Java 语言,固然 Android 开发也是基于 Java 语言,因此在 Android 中咱们能够用 Junit4 单元测试框架进行回归测试,但同时,Google 也提供了一个 AndroidJUnit4 测试框架,看名字就知道它是基于 JUnit 4 框架适合在 Android 环境中作单元测试。

那么,AndroidJUnit4 和 Junit4 有什么区别呢?很大一个区别在于:

1,AndroidJUnit4 测试能够在真机的环境下进行。好比你要测文件读取SD卡,或者操做 SqlLite 数据库,这些条件只有在真机上才有的,此时你用 AndroidJUnit4 框架测试,能够直接跑起来用真实的环境作相应的单元测试。

2,JUnit4 测试是运行在工程项目中,也就是在编译阶段。此时若是想要模拟 Android 环境,好比我想用 JUnit4 来测试 Activity 类,那么就须要引用第三方库来支持,引用 Mockito 和 Robolectric 框架来模拟 Android 环境进行相应的单元测试。

因此什么时候用 AndroidJUnit4 和 JUnit4 不一样的框架进行单元测试,就看你待测试的方法前置条件是什么,而后作不一样的选择。

小结

总的来讲,单元测试不是集成测试,单元测试只是测试一个方法单元,不是测试一整个流程。集成测试是一种End To End的系统测试,测试相关模块集成在一块儿是否可以按照预期工做,通常都是接口或者功能层面的测试,可能会依赖不少系统因素,测试的代码逻辑通常比较复杂,运行时间会比较长,出错以后的修复成本高。单元测试则是开发者在集成测试以前就已经进行自测过,同时呢,进行单元测试以后,对于某个方法的执行路径组合进行了一一验证,它只关注三个目标:

  • 有明确的返回值。好比对某个函数进行单元测试,验证其返回值是否符合预期结果。
  • 这个函数只改变其对象内部的一些属性或者状态,函数自己没有返回值,就验证它所改变的属性和状态。
  • 一些函数没有返回值,也没有直接改变哪一个值的状态,这就须要验证其行为,好比点击事件。

阅读扩展

源于对掌握的Android开发基础点进行整理,罗列下已经总结的文章,从中能够看到技术积累的过程。
1,Android系统简介
2,ProGuard代码混淆
3,讲讲Handler+Looper+MessageQueue关系
4,Android图片加载库理解
5,谈谈Android运行时权限理解
6,EventBus初理解
7,Android 常见工具类
8,对于Fragment的一些理解
9,Android 四大组件之 " Activity "
10,Android 四大组件之" Service "
11,Android 四大组件之“ BroadcastReceiver "
12,Android 四大组件之" ContentProvider "
13,讲讲 Android 事件拦截机制
14,Android 动画的理解
15,Android 生命周期和启动模式
16,Android IPC 机制
17,View 的事件体系
18,View 的工做原理
19,理解 Window 和 WindowManager
20,Activity 启动过程分析
21,Service 启动过程分析
22,Android 性能优化
23,Android 消息机制
24,Android Bitmap相关
25,Android 线程和线程池
26,Android 中的 Drawable 和动画
27,RecylerView 中的装饰者模式
28,Android 触摸事件机制
29,Android 事件机制应用
30,Cordova 框架的一些理解
31,有关 Android 插件化思考
32,开发人员必备技能——单元测试

相关文章
相关标签/搜索