如何测试

图 48: Mock Server
UI 测试在传统的软件开发中,UI测试多数是由人手动来完成的。而在稍后的章节里,你将会看到这些工作是可以由机器自己来完成的——当然,前提是我们要编写这些自动
化测试的代码。需要注意的是 UI 测试并不能完全替代手工的工作,一些测试还是应该由人来进行测试——如对 UI 的布局,在现阶段机器还没有审美意识呢。
自动化 UI 测试是一个缓慢的过程,在这个过程里我们需要做这么几件事:
- 运行起我们的网站——这可能需要几分钟。
- 添加一些Mock的数据,以使网站看上去正常——这也需要几分钟到几十分钟的时
间。
- 开始运行测试——在一些依赖于网络的测试中,运行完一个测试可能会需要几分
钟。尽管可以并行运行测试,但是一个测试几分钟算到最后就会累积成很长的时间。
所以,你会发现这是一个很长的测试过程。尽可能地将这个层级的测试往下层级移,就会尽可能的节省时间。一个UI测试需要几分钟,但是一个单元测试可能不到1秒。这
就意味着,这样的测试下移可以节省上百个数量级的时间。
如何测试
现在问题来了,我们应该怎么去写测试?换句话来说,我要测什么?这是一个很难的问题,这足够可以以一本书的幅度来说明这个问题。这个问题也需要依赖于不同的实
践,不同的时候我们可能对问题的看法都有不同。
编写测试的过程大致可以分成下面的几个步骤:
- 了解测试目的 (Why)?即我们需要测什么,我们是为了什么而编写的测试。
测试的点,在不同的条件下这个测试点是不一样的。
- 我们要如何进行测试 (How)?我们要使用怎么样的方法进行测试?
测试目的我们在上面提到过的测试金字塔,也表明了我们在每个层级要测试的目的是不一样的。
在单元测试这一层级,因为我们所测试的是每一个函数,这些函数没有办法构成完成的功能。这时候我们就只是用于简简单单的测试函数本身的功能,没有太多的业务需
求。
而对于服务这一层级,我们所要测试的就是一个完整的功能。对于以 API 为主的项目来说,实际上就是在测返回结果是否是正确的。
最后 UI 这一层级,我们所需要测试的就是一个完整的功能。用户操作的时候应该是怎样的,那么我们就应该模仿用户的行为来测试。这是一个完整的业务需求,也可以
称之为验证测试。
测试点在了解完我们要测试的目的之后,我们要测试的点也变得很清晰。即在单元测试测试我们的函数的功能,在我们的服务测试我们的服务,在我们的 UI 测试测试业务。
而这些都理想的情况,当系统由于业务的原因不得不耦合的时候。究竟是单元测试还是功能测试,这是一个特别值得思考的问题。如果一个功能即可以在单元测试里测,
又可以在服务测试里测,那么我们要测试哪一个?或者说我们应该把两个都测一遍?而如果是花费时间更长的 UI 测试呢?这样做是不是会变得不划算。
如何写测试代码先让来们来简单地看一下测试用例,然后再让我们看看一般情况下我们是如何写测试代码的。下面的代码是一个用 Python 写的测试用例:
class HomepageTestCase(LiveServerTestCase):
def setUp(self):
self.selenium = webdriver.Firefox()
self.selenium.maximize_window()
super(HomepageTestCase, self).setUp()
def tearDown(self):
self.selenium.quit()
super(HomepageTestCase, self).tearDown()
def test_can_visit_homepage(self):
self.selenium.get( '%s%s' % (self.live_server_url,"/")
)
self.assertIn("Welcome to my blog", self.selenium.title)
在上面的代码里主要有三个方法,setUp()、tearDown()和test_can_visit_homepage()。
在这三个方法中起主要作用的是 test_can_visit_homepage() 方法。而 setUp() 和 tearDown()是特殊的方法,分别在测试方法开始之前运行和之后运行。同时,在这里我
们也用这两个方法来打开和关闭浏览器。
而在我们的测试方法 test_can_visit_homepage() 里,主要有两个步骤:
- 访问首页
- 验证首页的标题是 “Welcome to my blog”
大部分的测试代码也是以如何的流程来运行着。有一点需要注意的是:一般来说函数名就表示了这个测试所要做测试的事情,如这里就是测试可以访问首页。
如上所示的测试过程称为 “四阶段测试”,即这个过程分为如下的四个阶段:
- Setup。在这个阶段主要是做一些准备工作,如数据准备和初始化等等,在上面
的 setup 阶段就是用 selenium 启动了一个 Firefox 浏览器,然后把窗又最大化了。
- Execute。在执行阶段就是做好验证结果前的工作,如我们在测试注册的时候,那
么这里就是填写数据,并点击提交按钮。在上面的代码里,我们只是打开了首页。
- Verify。在验证阶段,我们所要做的就是验证返回的结果是否和我们预期的一致。
在这里我们还是使用和单元测试一样的 assert 来做断言,通过判断这个页面的标题是 “Welcome to my blog”,来说明我们现在就是在首页里。
- Tear Down。就是一些收尾工作啦,比如关闭浏览器、清除测试数据等等。
Tips需要注意的几点是:
- 从运行测试速度上来看,三种测试的运行速度是呈倒金字塔结构。即,单元测试
跑得最快,开发速度也越快。随后是服务测试,最后是 UI 测试。
- 即使现在的 UI 测试跑得非常快,但是随着时间的推移,UI 测试会越来越多。这
也意味着测试来跑得越来越久,那么人们就开始不想测试了。在我们之前的项目
全站分卷索引 · 119 卷
- 1Growth: 全栈增长工程师指南
- 2软件开发的核心难题:沟通
- 3大公司的专家与小公司的全栈
- 4全栈工程师的未来:无栈
- 5基础知识篇
- 6工具只是辅助
- 7语言也是一种工具
- 8提高效率的工具
- 9IDE
- 10终端或命令提示符
- 11包管理
- 12环境搭建
- 13Windows
- 14GNU/Linux
- 15学好一门语言的艺术
- 16输出是最好的输入
- 17如何应用一门新的技术
- 18Web 编程基础
- 19从 HTML 到页面显示
- 20HTML
- 21中文?
- 22其他 HTML 标记
- 23小结
- 24CSS
- 25简介
- 26样式与目标
- 27更有趣的 CSS
- 28JavaScript
- 29JavaScriptFul
- 30面向对象
- 31其他
- 32前端与后台
- 33后台语言选择
- 34PHP
- 35Model
- 36View
- 37Controller
- 38后台即服务
- 39后台即服务
- 40数据库
- 41搜索引擎
- 42前端框架选择
- 43前台与后台交互
- 44JSON
- 45WebSocket
- 46编码过程
- 47Web 应用的构建系统
- 48Web 应用的构建过程
- 49Web 应用的构建实战
- 50Git 与版本控制
- 51Tasking
- 52Tasking 开发任务
- 53写代码只是在码字
- 54内置索引与外置引擎
- 55内置索引与外置引擎
- 56如何测试
- 57测试替身
- 58Mock
- 59测试先行
- 60可读的代码
- 61命名
- 62函数长度
- 63代码重构
- 64提炼函数
- 65内联函数
- 66查询取代临时变量
- 67重构到设计模式
- 68上线
- 69隔离硬件:虚拟机
- 70隔离操作系统:容器虚拟化
- 71隔离底层:Servlet 容器
- 72隔离依赖版本:虚拟环境
- 73隔离语言:DSL
- 74GNU/Linux
- 75HTTP 服务器
- 76数据库端缓存
- 77前端缓存
- 78运行机制
- 79自动化部署
- 80依赖与包仓库
- 81构建软件包
- 82数据分析
- 83想法-构建
- 84产品-衡量
- 85数据分析
- 86分析数据
- 87用户数据分析:Google Analytics
- 88流量获取
- 89移动应用
- 90网站性能
- 91SEO
- 92什么样的网站需要 SEO?
- 93内容
- 94UX 入门
- 95什么是简单?
- 96进阶
- 97认知设计
- 98持续交付
- 99持续集成系统
- 100持续交付
- 101持续部署
- 102持续阅读
- 103遗留系统与修改代码
- 104遗留代码
- 105修改遗留代码
- 106速度优化
- 107模块重构
- 108Retro
- 109三个维度
- 110架构模式
- 111预设计式架构
- 112演进式架构:拥抱变化
- 113意图导向
- 114重构
- 115模式与演进
- 116相关阅读资料
- 117架构解耦
- 118CQRS
- 119CQRS 结合微服务