测试点
选择的测试点有两个
- 一个是用户与浏览器(客户端)之间的节点,也就是模拟用户对浏览器的操作与获取的响应来进行测试,称之为“前测试点”(Front Test Point)。
- 一个是浏览器(客户端)与服务器之间的节点,也就是模拟客户端来向服务器收发HTTP请求来进行测试,称之为“后测试点”(Back Test Point)。
我们没有在服务器内部设置测试点,也就是说我们将服务器视为一个黑盒。
测试阶段目标(Roadmap)
- alpha阶段:
- 搭建自动测试环境
- 在后测试点,实现测试逻辑和测试数据分离,为持续测试做基础。
- 在前测试点,实现自动化测试,为持续测试做基础。
- 检验各功能在理想条件下是否如规格书所描述地运行。
- 理想条件:完全符合预期的简单输入。
- 搭建自动测试环境
- beta阶段:
- 鲁棒性检查:检验边界条件,在非异常的极端/特殊情况下各功能是否如规格书所描述地运行。
- 在后测试点,构建复杂测试样例。
- 在前测试点,构造usercase模拟一套用户的操作,并在此基础上实现并行测试。
- 并行测试:构建多个usercase,随机伪并发执行,检验是否运作正常。
- 兼容性检查:测试在不同终端、不同平台、不同浏览器上的运行情况。
- 不同终端:mobile、PC
- 不同平台:mac OS, windows, android, ios
- 不同浏览器:chrome, edge, firefox
- 鲁棒性检查:检验边界条件,在非异常的极端/特殊情况下各功能是否如规格书所描述地运行。
- gamma阶段:
- 易用性检查:检验是否存在不合理的设计/不易用的情景。
- 良好的响应性。
- 快捷的操作。
- 直观的反馈。
- 需求的满足程度。
- 安全性检查:使用攻击性的测试思路,挖掘安全性漏洞。
- 泄露敏感信息的代码、包、数据、接口。
- 可以被利用的接口。
- 在被攻破后的可执行的应急措施。
- 易用性检查:检验是否存在不合理的设计/不易用的情景。
各阶段出口条件:
- alpha:在理想条件下运行符合规格描述。
- beta:通过鲁棒性、兼容性检查。并通过alpha阶段的回归测试。
- gamma:通过安全性检查。并通过alpha, beta阶段的回归测试。
测试工具
测试架构完全使用Django的django.test模块。
服务器端对两个测试点使用不同的做法:
- 对于前测试点,因为需要在js代码中指定后端的域名+端口,所以无法使用具有随机端口的django测试服务器。所以我们每次进行前测试的时候,都需要手动刷新一下本地的服务器,将测试数据填充进去。
- 对于后测试点,直接使用django的fixture系统来填充测试服务器。
客户端对两个测试点采用不同的工具来模拟:
- 对于前测试点,使用Selenium模拟客户端。
- 对于后测试点,使用Django原生的Client模拟客户端。
前测试点
设计模式
使用Page Object作为Design Pattern。即,将每个页面作为一个类,将该页面提供的服务作为接口。每个类内部自己维护该页面的元素定位符。
测试环境的搭建
使用Fiddler对域名和端口进行重映射,将对远端服务器的请求转换为对本地服务器的请求。
不过要注意一点,因为本机环境下无法使用https(django不支持),所以需要手动将前端代码中的所有https都替换成http。
代码覆盖率计算方法
目前没有。
尝试过jscover,但jscover的原理是对js代码插桩,并使用一个js全局变量来存放覆盖率结果。然而js全局变量无法跨页面存在,所以一旦一个测试样例中出现了页面跳转,那么覆盖率就会丢失一部分。而我们的网站目前是一定要求从首页进入的线性访问模式,故而页面跳转是必须的。所以目前无法使用jscover来获取代码覆盖率。合适的替代品目前仍未找到。
测试思路
细的来说:
- 检查用户需要知道的信息的元素是否出现在页面上。
- 检查页面上是否出现了不该出现的元素。(例如已经登录的用户却在界面上找到了登录按钮)
- 检查用户操作是否得到预期的响应。
- 检查页面跳转逻辑是否如逾期执行。
- 检查异常处理是否合理完善。
粗的来说:
- 检查典型用户的一套操作流程是否能正常执行,并且用户是否能够的得到他们想要的信息。
- 检查用户的异常操作是否会得到合理的报错,并能顺利恢复现场。
测试样例总览
此处不将列出详细的测试用例内容,只列出每族测试样例的概述。
+号表示还未完成,或可能与已经写的测试样例重复。
- +内容检查
- 搜索结果页面的课程信息是否与课程信息页面的课程信息一致
- 课程信息页面是否给出评论信息
- 首页的“选择学院”能否给出所有学院
- 页面跳转逻辑检查
- 各页面的跳转逻辑是否与规格一致
- Addition(规格里没提到的):
- 首页 => 搜索
- 搜索课程按钮
- 搜索框内回车
- 注册 => 首页
- 首页按钮
- 注册 => 登录
- 登录按钮
- 确认注册按钮
- 登录 => 首页
- 首页按钮
- 确认登录
- 登录 => 注册
- 注册按钮
- 首页 => 搜索
- 功能检查 & 鲁棒性检查
- 登录功能
- 是否能登录到一个已注册用户上
- 是否不能登录到一个未注册用户上
- 在登陆后是否在各场景下都能正确反映登录用户信息
- 评论后该评论的作者是否是登录用户
- 个人信息页面是否是登录用户的信息
- 注册功能
- 是否不能注册一个已注册用户
- 是否能注册一个未注册用户
- 注销功能
- 在各页面是否能正常注销
- 评论功能
- 是否能在对应课程下给出相应的评论
- 这个好像和上面的登录功能里面的评论重了,一起做了
- 是否能在对应课程下给出相应的评论
- 搜索功能
- +是否能通过课程信息页面的一些条项搜索对应的内容
- 是否能搜索到确实存在的课程
- 是否会搜索到不存在的课程
- 在指定学院的情况下能否正常执行
- 在不指定学院的情况下,能否给出所有课程
- 在只指定学院的情况下,能否只给出该学院的所有课程
- 在课程名称、学院都被指定的情况下
- 当课程名称不属于该学院时,能否不给出该课程
- 当课程名称属于该学员时,能否给出该课程
- +模糊搜索是否有效
- TODO 是否存在非法的搜索字符?
- +切页功能
- 搜索结果、课程信息页面的切页功能是否能正常工作
- 登录功能
- +页面冗余检查
- 在未登录情况下是否存在个人信息、注销按钮。以及登录情况下是否存在登录、注册按钮
- +兼容性检查
- 页面长宽比兼容性检查:在不同长宽比的浏览器界面下是否都能有良好响应
- 浏览器兼容性检查:在不同浏览器中是否都能有良好响应
- 分辨率兼容性检查
- 应该不做这个
- +易用性检查
- 在登录/注册信息不完整/错误的情况下能否给出有效提示引导用户完善信息
- 在评论超字数的情况下能否给出有效提示引导用户
后测试点
前提
我们默认一切规格规定的渠道的用户输入都已在前端被充分检验正确性(例如,注册时用户名、密码是否符合格式),故在后端不做任何相关测试。
代码覆盖率计算方法
使用python的coverage获取代码覆盖率。仅计算rateMyCoure目录下的代码。
测试思路
- 检查各接口是否如规格描述地正确响应。
- 检查是否存在不该暴露给用户的资源也暴露了。
- 使用代码覆盖率,检查是否存在无用代码。
测试样例总览
此处不将列出详细的测试用例内容,只列出每族测试样例的概述。
- 标准检查:对于非常良好的输入的情况下,各接口是否给出正确输出。
- 边界检查:对于满足传入需求,但处在边界的输入,各接口是否能给出正确输出。
- TODO
- 安全性检查:是否存在能在无权限的情况下获取敏感信息的接口,或在无限制的情况下占用过多服务器资源的接口。
- 在未登录情况下是否能访问个人信息,及已登录情况下能否访问其他用户的个人信息。
- TODO 可能还有。
- 异常检查:在出现异常情况时,服务器的响应情况。
- 我们应该不做这个。
- 压力测试
- 我们应该也不做这个。
测试样例构造思路
这里只将给出部分比较抽象的测试样例的构造思路。
标准检查-同质合并
注意到有大量的接口都是Create, Update, Search这类对Model的操作,考虑它们的同质性。
观察可知同质性:
Create, Update: 都是发送Post请求,并将修改的Model信息附加在payload上。收到回复后检查回复请求中的状态码来确定是否成功,最后检查数据库中是否有符合要求的Model被添加/更新。
Search: 都是发送Get请求,并将期望的Model信息附加在payload上。收到回复后检查回复请求中的状态码来确定是否成功,最后检查回复请求中body的信息是否符合预期。
也就是说大多数的测试样例之间的区别仅仅在于
- 请求的url
- 请求的payload
- 检查的Model/Body内容
故而可以将这部分数据抽离出来单独存放,使用统一的逻辑进行测试。
测试代码管理
测试代码和服务器代码不在一个库中,它独立地作为一个库存在。但主库(服务器代码所在库)会将测试代码作为submodule引入。
这么做的目的是为了使得任何时候都能从主库的任意分支获取测试代码的任何分支的任何commit,避免了因为测试需要而对主库代码的合并/切出作出要求。
测试样例管理
我们使用了django提供的tag来管理测试样例,使得在测试时可以选取测试样例执行。目前使用的tag包括
- front
- 该测试样例为前测试点测试样例。
- back
- 该测试样例为后测试点测试样例。
- db_modify
- 用于前测试点,该测试样例会修改数据库,每次使用前需要刷新数据库,重新加载测试数据库。
- split
- 用于前测试点,该测试样例用于测试切页,需要加载额外的数据库来进行测试。
- 待废弃。
- auto
- 用于后测试点,该测试样例分离了测试逻辑和测试数据,它会加载json文件来执行测试。
- foreign
- 用于后测试点,该测试样例使用了Model的外键,目前无法分离这部分的测试逻辑和测试数据。
- 待废弃。
Alpha阶段测试结果
前测试点
commit: 666cc6afa8556d0618d630e9118f1df88518e994
共47个测试样例,全部通过。
- bug数:4
- invalid数:2
目前没有找到合适的工具来和selenium配合获取代码覆盖率。
后测试点
commit: 55890581df5543ce2e34768306f72bf01e62c867
共31个测试样例,全部通过。
- bug数:4
- invalid数:8
代码覆盖率: