测试在软件开发中的位置可谓举足轻重。几乎所有讲软件工程的书都会提到并且强调其重要性。测试在构建软件的作用非常明显,尤其是当你构建大型应用的时候。
本篇文章主要由四部分组成:
- 什么是测试
- 为什么要测试
- 测试的方法
- 自动化测试
测试就是保证你的代码按照预期运行的代码。
测试就是代码,和普通代码除了功能之外没有区别。 测试的功能就是确保被测试的代码按照预期运行。
如何确保
呢? 通过断言
。
怎么才能按照预期
呢? 这就需要你充分考虑业务场景了。 高的测试覆盖率
是优秀代码的特征。 如果你实现不知道怎么测试,那就先提高你的测试覆盖率吧。
高的测试覆盖率并不能反应代码质量高
高的测试覆盖率是好的代码的必要条件,因此想写好代码,先把你的测试覆盖率提高再说吧。
测试用例
会收集包括软件哪一部分,哪一个分支甚至哪一条语句执行的信息。
测试覆盖率是一个技术指标,用来衡量被测试代码占所有代码的比例。
如下是我写的一个 sample 的测试覆盖率报告:
这里测试覆盖率有了更多的精细化的技术指标: 比如语句覆盖率(Stmts),分支覆盖率(Branch),函数覆盖率(Funcs),行数覆盖率(Lines),未被覆盖的行(Uncovered Line)等。这些指标通过名字就大概能看出含义。
测试可以让你安心,它给你自信,它告诉你“嗯!你的代码没有问题”,它给了你 自信,这样的信息在构建大型项目是很重要的。
我的编程习惯是文档驱动,测试驱动,也就是说在做一个需求之前,先写下文档然后写测试用例,再写下实现的步骤(TODO),最终填充代码实现。这个模式可能和大家的编程习惯不太一样,甚至是完全相反的。 不过从我的经验来看,这个习惯给我带来了很多好处,我希望你也可以尝试一下。
程序员最不愿意做的事情除了临时需求变更之外恐怕就是改别人的代码了。 改别人的代码需要充分了解当时的场景,包括业务,基本假设是什么,除此之外还要看懂别人的每一行代码,我们才有信息去更改别人的代码。这是一个非常痛苦的过程。有了测试了用例情况就有所不同了。
在测试用例写的足够完善的情况下,他们只要保证改了代码测试用例可以通过了, 他们就有信息去修改你的代码了。
如果没有测试用例,发布新的功能和修复一个线上bug是非常痛苦的。 毕竟修复一个bug,引入两个bug的梗不止一次地出现在我们的真实生活之中。 你如果非常了解这个项目倒还好,如果不呢? 这会让你举步维艰,仿佛陷入了一个无尽的沼泽。 因此完善的测试确实可以让你放心的按下确认发布按钮。
尤其是在敏捷团队中,发布和修复线上bug是一个非常频繁的操作,你如果不希望天天提心吊胆修改代码,那么从现在开始完善你的测试用例吧!
如果你不想从头到尾把代码看一遍。那么直接去看测试用例往往是一个快速的方式。 从测试用例我们不仅可以看到代码有哪些功能,我们设置可以看到代码能够处理的和不能处理的东西。 这些东西都是一目了然的。 我甚至在接手一个项目之前会优先看他的package.json和test文件夹。
前者可以看出项目的依赖组成,有哪些脚本。 后者可以看出项目具体的功能点
测试的类型有很多,不同维度去划分也会产生不同的类型。 这里讲以最常见的划分方法划分的测试种类。 枯燥的术语往往是比较难以理解的,希望你不会被这些术语给吓到。
我们先来看下最最基础的测试类型-单元测试。
单元测试或许是最简单最常见的测试类型了。
单元测试就是测试一小块代码的测试,这一小块代码可以是一个函数, 一个模块或者一个类等
单元测试同时也是最容易编写的,最容易被理解的测试类型。 单元测试总是设定一个环境,然后给定一个输入,检测程序的输出。
输入也可以是一个函数
如果你写过单元测试的话,你会发现有些东西非常容易写单元测试,而有些却非常难以书写。 更进一步我们发现那些难以书写单元测试的代码大都是依赖别的模块或者被别的模块依赖,换句话说是有副作用的,是不纯粹的。
非常容易写单元测试的代码是那些于IO/UI等无关的代码。
IO/UI 相关的可以是ajax,localStorage,dom等等
如果你确实依赖于外界(比如IO/UI),你需要在进行单元测试的时候去mock他们。 因此,尽量限制代码的副作用在可控的范围是一件非常重要的事情
试试函数式编程吧。
在我们讲解集成测试之前呢,我们来看下为什么我们需要集成测试。
单元测试确保了软件的每一个部件运转正常,而集成测试确保了它们在一起的时候运行正常。
独立运行正常并不意味着集成起来就正常,否则也就不会有集成测试了。
那么为什么独立运行正常,集成起来就有可能不正常了呢?
原因就在于我们的应用是有副作用的。 数学和计算机学友一个概念叫幂等(idempotent、idempotence)。这个概念在 后端会比较常见,前端很少会用到这个概念。后端幂等指的是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。
那么对于前端也是类似的,如果我们的系统完全幂等。那么集成测试就显得不重要了。当然这个是不可能的。另外一个原因在于你各个部分正常运行,但是将各个部分组合到一起的部分,有异常(这部分是无法被单元测试覆盖到的)。因此集成测试是很有必要的。
集成测试关注的是各个部分的交互和相互作用。
集成测试就是将单元代码放到一起,看它们是否正确运行。
端到端测试相对来说比较昂贵,测试的代价会比较大,并且这部分占所有测试的比重也是比较低的。 但是不意味着不重要。
这部分主要关注的是真正的用户行为是否正确。前面两种测试更侧重于技术性,这部分则是完全站在产品角度,站在应用功能角度去测试。