提示:阅读本章之前,请先阅读目录
软件测试,200道真题测试面试题
在工作当中,我用到的最多的方法是,边界值,等价类,场景法
第一个呢,是边界值,针对测试经验给我的反馈,大量的软件程序之间的错误,在输入端这边的错误,大部分都是因为输入或者输出在范围边界上,比如,一个整数大于0,小于等于5,那么,我们就可以得到一些数值,就是-1,0,1,4,5,6,那么,这些数值就是我们当前要输入的值的一个边界,那我们就可以根据这些值来设计测试用例。
第二个,就是等价类,分为有效等价类,以及无效等价类,在我们输入范围的子集里面,对软件程序运行是正向的,那么就是有效等价类,而在这个范围子集之外的,就是超出程序设计的范围之外,就是无效等价类。
第三个,场景法,就是把系统全部业务流程都梳理出来,然后每个业务流程的分支也梳理出来,然后,我们梳理出来正向的流程,以及反向的流程之后,我们就去设计在每条流程可能会经历的测试行为是什么?在流程中间,我们可以输入什么样的数据,或者,执行什么样的操作,可以转到其他流程,然后再转到正常流程上,让整条流程能够跑通。场景法中,我们都会结合边界值和等价类的设计方法,来对我们的系统有一个全面的覆盖测试。
为什么要进行接口测试的话,我总结了四个点
第一个就是,我们在进行功能测试的时候,往往只是针对前端页面的功能测试,即使前端有较为良好的数据格式校验,但是可以通过一些工具,来绕过我们的前端校验,直接调用接口,这样,就会导致,我们前端页面的校验完全失效,因此,我们就需要对接口进行测试,绕过前端,直接校验接口,来发现在页面发现不了的BUG。
第二个就是,检查系统对于异常的处理能力,对于接口,如果传入一些异常的数据,是否会导致服务器崩溃,从而导致一些代码的泄露,所以,进行接口测试,是非常有必要的。
第三个就是,检查系统的安全性,我们知道,互联网中会存在非常多的黑客恶意攻击服务器,导致数据的泄露,一些注入攻击,代码审查等,如果,我们的接口没有对这些恶意攻击进行处理,那么,就有可能导致我们的系统被攻击入侵,从而导致直接的经济损失,所以,对于接口的测试,是有一定的程度来检查我们系统的安全性。
第四个就是,保障服务端的质量,避免我们的版本更新迭代,会导致服务端不稳定,在我们前端调用接口的时候,是需要返回一个稳定的处理结果,否则的话,也会导致前端的功能的不稳定,所以,要想确保前端功能的稳定,就需要确保服务端的质量。
这个主要有两个处理的方向。
第一个,就是,自己复现细节,试试看能不能把bug复现出来。在我们去复现的时候,一定要注意版本,比如,我们是在1.2的版本里面发现了这个bug,那么,我们就要去这个1.2的版本去复现这个bug,而不是在其他版本去复现,因为,在新的版本,开发人员可能自己发现了这个bug,然后直接修复了,没有跟测试人员进行沟通,这个情况是有的。那么,如果想要增加复现的几率呢,我们需要看看有没有一些运行日志,或者错误信息,来辅助我们进行复现。
第二个,就是,我们跟开发人员去沟通这个bug,把我们的操作步骤,操作细节,输入的数据,还有bug的详细信息,都给到开发人员,跟开发人员进行沟通,看看开发人员是什么样的反馈,因为开发人员的开发经验是比较丰富的,对于一些bug的产生,是有一个非常清楚的认知是可能因为什么原因导致这个bug,并且是有可能复现不了的。所以,当我们自己复现不了的时候,是可以跟开发人员进行沟通的。
那么这个bug实在是无法复现怎么办呢?
我们首先要对bug进行分级,看看这个bug,是不是会影响到我们正常业务,如果是影响到了业务的执行,或者是,会让用户产生不好的体验,优先级高的bug,那么,我们就要全力去复现,因为这个bug是比较重要的,如果实在是找不到的话,我们可以等后续版本的更新,看看是不是开发人员,在修复其他功能的时候,可以一起修复了,因为很多时候,可能是另外一个功能影响这个功能,功能之间有关联。
当然,如果这个bug,不是那么重要,就是不会造成一些不好的体验,或者是不会影响到用户的正常使用,那么,我们在全力复现之后,还是无法复现,那么,我们就可以先放一放,先提交到缺陷管理平台,去记录这个bug的信息,在后续的版本中,我们多留个心眼,看看能不能重新复现。
主要是以下的信息,我们从开发人员来修复这个bug的角度来说。
bug标题,开发人员当然是希望,在开始bug的修复之前,先看这个bug标题的描述,然后能够快速的了解这个bug的情况,需要直击关键点,哪个模块哪个功能,经过什么样的行为,出现了什么bug
bug等级,我们测试人员,需要根据这个bug等级的规范,来确定这个bug的严重等级,以便于开发人员,对于一些严重等级高的优先处理
bug的优先级,我们测试人员,需要根据这个优先级的规范,来定义bug的优先级,以便于开发人员,对优先级高的bug,进行优先的修复解决,避免影响到当前版本的bug修复进度
bug对应的软件版本,这个bug是出现在哪个版本上,这个也很重要,对开发人员可以快速定位bug,然后修复
bug的操作步骤,对于这个bug的复现,是经过什么样的操作步骤,然后产生的这个bug,这个以便于开发人员按照这个步骤去复现这个bug
bug的输入数据,对于这个bug,我们输入一些什么样的数据,就会导致bug的产生
bug的期望解决结果,我们需要给到开发人员,清晰的期望结果,希望这个bug解决到什么样的程度,达到什么样的结果
bug的错误信息,我们主要是以截图为主,把这个bug出现的情况,截图,上传到附件,也可以上传日志,对于一些操作步骤复杂的,可以录制视频上传
bug的指派,我们需要通过分析,这个问题可能是前端还是后端的问题,然后指派给对应的开发,提升bug处理的效率,否则的话,前端也不知道这个bug是由前端解决的,后端也不知道这个是不是该由后端解决的
回答1:
在我以往的测试中,我就遇到了一个非常搞笑的bug,就是,个人信息的出生日期控件,前端页面呢,是让用户自己选择自己的出生日期,第一个选项是年,第二个是月,第三个是日,然后呢,这个bug就是,在我们选择2月份的时候,第三个日的选项,居然可以选择31,这个明显就是,前端没有对日期的格式进行校验,然后我就提交bug给到了前端,然后前端进行了修复,根据用户选择的日期之后,会进行格式的校验。
回答2:
在我以往的测试中,我在测试分页功能的时候,用户可以输入一个数,然后到达指定的页数,然后这个输入框,只限制了只能输入数字,然后不能输入中文,英文这些字符,然后,我就尝试输入1.5,2.5这样的,带有小数点的数字,然后点击跳转之后,然后直接返回了服务端报错的页面,是服务端抛出异常的代码,然后,我就给到了后端这个bug,然后紧急进行修复了,这个是我测试工作中,遇到的印象比较深刻的,比较经典的bug。
先说一下思路,就是,笔和其实跟软件程序的测试概念是不太一样的,软件程序的测试本质上就是输入和输出的测试,测试程序输入之后可能会出现什么bug,测试程序输出的过程中可能会产生什么bug,那有相同点的地方就是,软件质量的六大特性,测试的本质就是测试它的一个质量,那软件质量的六大特性,分别就是,功能性,易用性,可靠性,效率性,可维护性,可移植性。
那么,我们就可以根据这些特性来测试我们的笔,
功能性,可以测试它最长连续使用的时间是多少,连续使用会不会出现断触,是不是在任何纸质上都可以使用
易用性,是不是所有人群都可以使用,不分男女老少,是不是拿起来就能使用。
可靠性,在经过100个人的使用,是不是还能够正常的使用;连续使用之后,会不会损坏;
效率性,能不能写上比其他普通的笔更多的字;
可维护性,能不能把笔帽,笔芯换成新的;
可移植性,能不能跑到另外一个地方的纸上使用;能不能把里面的部分,拆出来然后装到其他同款型号的笔上使用;
在进行web的兼容性测试的时候,一般都是测试浏览器的兼容性,就是测试web页面,在不同浏览器的展示样式,以及功能的使用上,有没有什么异常。
主要我们会测试chrome浏览器,火狐浏览器,safari浏览器,360浏览器,oprea浏览器,Egde浏览器
出现比较多不兼容的情况,我之前遇到过就是,不同浏览器它的内边距padding和margin的默认值不一样,就会导致页面的最上边和最左边,会产生一个空白的间隙,这个原因是没有清除默认样式导致的。
还有就是js脚本的兼容,在不同的浏览器,可能有一些js的版本,会导致该浏览器的版本无法兼容js的语法,然后导致页面功能失效。
monkey指令,其实,实际上就是安卓的一个操作指令monkey,它在安卓系统中,有个monkey.jar的包,我们可以通过adb shell monkey来调用它,比如,我们可以通过-p,来指定运行的app,然后monkey是通过随机性的事件来执行操作,比如,点击,拖动等操作,我们是没有办法直接控制monkey的操作步骤,因为它是随机产生事件的,如果我们想复现上一次操作的bug,我们可以使用-s,来指定这个随机产生的种子数,比如-10,那么,第一次运行和第二次运行,会是一样的。
如果我们一定要指定monkey的操作步骤,那么我们通过adb shell monkey是实现不了,但是monkey提供了一个脚本的方式,我们创建一个脚本代码,这个脚本的文件格式,是txt,然后里面编写好每一步的操作步骤,比如,点击哪里,这个是需要坐标系的数据,然后,我们通过push把这个文件传到安卓设备上,然后再通过monkey -f 来执行这个脚本。
Selenium的运行原理,实际上它不会直接去操控浏览器,而是通过一个webdriver的服务,我们在配置web自动化测试环境的时候,我们需要根据浏览器的类型,去下载我们的webdriver,这里的意义就是,通过webdriver这个服务去控制浏览器,完成我们的操作。那么,整体运行原理就是,我们通过编写脚本代码,调用selenium封装好的各种操作方法,然后selenium就会运行webdriver,然后webdriver就会在系统后台进程创建一个服务,然后去下方操作指令给到浏览器,浏览器再按照指令进行操作,然后浏览器操作完成之后,根据我们需要返回的数据,返回到webdriver,webdriver再传回selenium,然后,我们就可以拿到各种数据以及实现行为操作,这样就可以完成web的自动化。
首先,我们要清楚什么是动态元素。
动态元素,一般来说,就是那些属性或者路径会不断改变的元素,比如,动态id,刷新页面,每一次的元素id,都是发生变化的,所以,我们是没办法通过id去定位的,那么,这个时候,我们就可以选择比较灵活的定位方式,有xpath和css selector,一般来说,我们可以通过相对路径进行定位,然后选取这个动态元素,不会变的属性或者文本内容,如果会定位到多个元素,那么,也可以考虑先定位它的父级,然后再定位它本身,如果我们还是很难通过相对路径定位,也可以使用绝对路径,虽然说绝对路径不是推荐的定位方式,但是也是处理动态元素定位的一种办法,可以灵活使用。
第一个,检查是否添加了等待,有三大等待,显式等待,隐式等待,还有强制等待,如果我们没有等元素完全加载出来的话,是完全有可能定位失败的
第二个,检查定位的语法有没有错误,我们可以通过F12的开发者工具,然后按Ctrl+F,去校验我们的语法
第三个,就是我们可能定位到了多个元素,然后这个元素不在第一个,因为selenium默认选择的元素就是第一个,所以也有可能造成定位失败
第四个,窗口的句柄,是否进行切换,如果在原有的句柄操作之后,弹出新的窗口,那么句柄是需要进行切换的,可以通过window_handls获取所有的句柄,再通过switch_to_window进行切换
第五个,检查页面是不是存在frame框架,如果我们要定位的元素在不同的frame框架里面,那么,我们是需要通过进入这个frame框架,才能定位到
第六个,检查是不是被覆盖,有时候,页面会弹出新的广告元素,把要点击的元素进行覆盖,那么,也会造成定位失败,还有一种情况就是,浏览器被缩小了,这个元素没有被显示出来,这个时候,我们可以通过最大化浏览器窗口解决这个问题
在自动化测试过程中,数据驱动的形式,可以有很多种,比如,excel,yaml,txt,csv,xml等,其本质,就是存放测试用例的数据,通过数据来驱动自动化的测试。
那么,我们该如何选择数据驱动的形式
那么,最主要的,还是需要根据我们团队的测试人员的技术水平来选择,如果是技术水平较低,那么,我们可以选择excel,这种最常见的数据文件,因为,基本上人人都会使用excel,那么来编写测试用例,相对来说,是比较容易接受的,且学习成本低,我们只需要编写好使用文档规范,如何去编写测试用例然后执行自动化测试,测试人员只需要根据这个规范文档,去编写即可轻松实现自动化测试,而不需要去编写代码。
那么,如果我们的测试人员,技术水平是有基础的,是能够通过编写代码,实现自动化的测试, 那么,我们可以选择yaml,作为数据驱动的形式,yaml是比较直观,高效的数据形式,通过键值对的形式,其实,更符合编程逻辑,所以,有代码基础的测试人员,就可以根据我们的yaml规范文档,来编写测试用例,也可以实现自动化的测试。
关键字驱动是自动化测试框架中最为核心与底层的设计模式,适用于UI自动化与接口自动化测试。
本质意义上,就是面向对象编程的对象与封装,这种设计模式就是基于业务使用场景,进行合理独立封装,然后再通过调用封装好的函数来执行业务。
一般而言,封装的时候,都会考虑代码的复用性,以及封装的灵活度。
封装也会根据实际需求进行优化,从常态化操作的封装,再到业务流程的封装,以及固定步骤和数据的封装,封装的形式是多样化的。一般都会根据当前项目的需求,进行优化。
因此,关键字驱动设计模式对于自动化项目是适配性最强的设计模式。
在我以往的工作中,我用的最多的接口自动化测试框架,是python+requests+yaml数据驱动+logging+pytest+allure+jenkins,web自动化测试框架是python+excel关键字驱动+logging+unittest+unittestreport+yaml+jenkins实现持续集成。
PO设计模式,也叫POM设计模式,就是Page Object Model,页面对象模型
,PO模型是专门用于UI自动化中的,PO关注的核心是页面,而不是操作行为。
其思想就是,将复杂的业务流程进行切片,把完整的业务流程,切割成一个又一个的独立页面,最终将页面所需的顺序进行组装,最终实现业务流程的运行。
PO模型中,主要分为四层
base 基类层,封装了selenium的一些常用的操作,点击,获取元素,输入等一些共用的方法
pageobject 页面对象层,对当前页面的业务流程进行封装,组成成单个页面业务流程的执行
testcase,测试用例层,把所有的业务流程组装成完整的业务流程
testdata 数据层,存放业务流程中所需要的数据
PO设计模型,极大提升了代码的可维护性,所有的内容都是基于页面来管理,每一个页面的单独维护都可以对测试用例的执行进行同步的维护,降低了维护成本。同时,PO设计模型,对单一系统的自动化测试,有一个非常好的覆盖,因为都是基于当前系统的编码设计,所有页面都是基于当前系统进行封装的。
第一个,我们可以通过减少强制等待的使用,强制等待是造成selenium执行脚本效率低的主要原因之一,我们可以用显式等待和隐式等待,元素加载完成之后,立马执行下一步操作。
第二个,在selenium4.0版本及以上,可以通过chromeoptions来配置页面的加载策略,有三钟加载策略,分别是,normal,正常模式,就是等页面所有的元素和资源加载完毕,才进行下一步的操作,这也是selenium默认的策略;第二个是eger,就是等所有dom节点加载完毕,就会开始下一步操作,不会等资源是否都加载完毕;第三个是none,需要配合显式等待或者隐式等待,当我们需要定位的元素,加载完毕之后,就开始下一步操作,不会等全部资源都加载完毕
第三个,合理的设计与封装自动化测试框架,减少人为的介入,让自动化测试框架,可以在无人值守的情况下,自动执行自动化测试
第四个,减少不必要的操作步骤,因为selenium打开的浏览器,都是0缓存的,都是需要重新加载所有的资源,所以,我们可以通过简化进入测试页面的步骤,降低自动化测试执行的时间来提升效率。
第五个,我们还可以多线程的方式执行测试用例,可以用测试框架unittest或者pytest
第一,合理使用三大等待,在一些特殊的场景,如果需要用到强制等待,那么,我们是可以使用的,因为它对于自动化测试的稳定性是有益的,对于一些无法用显式等待或隐式等待解决的问题,该用的时候,就可以用强制等待
第二,检查定位元素的正确性,我们写在定位元素的定位时,我们可以先通过F12,来调试定位元素的代码,来保障正确性
第三,我们要对一些容易出现异常的操作,进行异常处理,也就是try…except,最常见的就是读取文件不存在,定位元素,变量不存在等,让异常可以被处理,而不是直接抛出错误,让整个自动化测试停止
第四,对于使用了多线程的自动化测试,我们需要减少每个测试用例之间的依赖,甚至是互相独立,不依赖,因为多线程的执行,是无法指定测试用例的执行顺序的。
第五,有独立的测试环境,测试数据,我们需要避免因为人为的操作,从而导致自动化测试中断
第一,应当提高代码的复用性,把一些共用的函数或方法,然后封装到共用类,通过这个类来调用我们所需要的函数,从而减少代码的冗余,提升代码的质量。
第二,应当根据当前业务,选择合适的设计模型,比如,web自动化,我们就可以用PO设计模型,使用设计模型的好处就是,可以增加代码的可维护性,分层设计的架构,可以更好的管理我们的脚本。
第三,在各类函数的封装上,要考虑灵活传参的形式,不要把函数的功能写死,要灵活,可以通过不同参数,实现不同的需求,让函数可以灵活多用,甚至一个函数可以解决多个需求,提升函数的利用率,来减少代码量
我之前公司的UI自动化测试框架,技术栈是:
python+unittest+excel+ddt+logging+openpyxl+unittestreport
这个是我们基本的技术框架,那为什么要去选择这样的技术框架呢,主要有以下几点的考虑
第一,python的话,在我们公司的团队,是主流的编程语言,所以说,用python的话,我们的学习成本会很低,而且上手是会快,当然,python也是目前做自动化最主流的编程语言
第二,unittest测试框架,因为在之前的项目中,主流用的就是unittest,所以,我们直接沿用这个测试框架,我们搭建框架的效率是非常高的
第三,excel关键字驱动,excel,我们主要是拿来做测试用例的编写,我们通过excel编写关键字驱动的业务流程,然后通过自动化测试框架来读取这个excel,来达到关键字驱动,所以说,我们这个框架,是以关键字驱动为核心
第四,ddt,参数化,我们会搭配unittest进行参数化的测试,可以非常便捷的执行关键字驱动
第五,logging,对于运行中产生的日志信息,我们都是通过logging来实现日志的输出以及日志的保存,对每一次运行的详细都进行记录和保存,以备在出现运行错误的时候,进行日志的排查,logging我们是会进行二次封装的
第六,openpyxl,这个是处理excel的库,它强大的地方,就是可以读取excel,也可以修改excel并保存,我们通过读取excel里面的测试用例,然后,我们会把测试用例的执行结果,重新输出到这个excel的测试用例的测试结果这个字段,当然,我们还会输出执行的开始的时间,结束的时间,以及如果报错了,我们还可以进行截图之后把这个截图的照片路径,输出到这个测试用例上,这样,我们就可以通过路径拿到这个照片查看错误的信息。
第六,unittestreport,这个是个开源的插件,这个插件,主要是可以查看更加丰富的测试报告,它是基于element UI的前端展示样式,所以,它会比HTMLtestrunner,会更加好看,而且还支持将测试用例排序,查询,分模块显示等,也有统计图等详细信息,当然,另外一个原因就是,它自己封装了一个多线程的方法,所以,通过它,我们可以轻松实现unittest的多线程执行测试用例
那么,技术框架的设计思路,大概就是分为三层:
PO设计模型+数据驱动+结构分层
这三层,可以实现三个特性,可维护性,可读性,可扩展性
基本的技术框架就是这些,然后,后续可以根据我们的需求,如果需要持续集成,那么就可以增加jenkins。
我们以HTTP的请求为例子
我们通过浏览器访问url,或者是通过工具访问url,大致流程都是这样
我这里以浏览器访问的方式来解释
首先,浏览器根据这个url的请求协议,进行发起请求,比如我这里的url是,http://www.baidu.com,那么,浏览器会以http的请求协议进行请求,请求之前会携带,三个部分,请求头,请求行,以及请求体,然后给到服务器,服务器接收到之后,根据url请求的资源路径是哪个,去调用对应的接口,然后进行处理,处理完之后,返回响应结果,然后浏览器收到响应结果之后,给到前端,前端再对响应数据进行解析,加载资源,最后就是浏览器渲染页面。
长连接和短连接,指的是http发送完请求之后,是否保留tcp连接通道,短连接就是发起完请求之后,立马关闭tcp通道,而长连接是继续保持tcp通道,但是保持的时间是会限定的,以及可能还会限制进行请求的次数,这个在后端是可以定义的。
那么,在HTTP1.0的协议版本下,默认是没有长连接的,在HTTP1.1的协议版本,长连接是默认开启的。
在请求头,有这样一个参数,就是connection:keep-alive,在HTTP1.1的协议版本,这个不设置,它也是默认长连接,但是,它一定是长连接吗?显然不是,因为它主要是通过后端的定义。
那么,这两种连接模式,如何选择?
我们可以根据当前业务场景,进行选择,因为两者,都有好处与坏处。
短连接,坏处就是,会频繁的发起请求,关闭请求,对服务端资源的消耗是非常大的,因为服务端要频繁的处理每一个请求的建立与关闭,所以,短连接只适用那些,只完成1,2次的请求,然后就不再请求的业务场景,这样就避免频繁占用服务器资源,用完立马关闭连接通道。
长连接,好处就是,长时间保持连接通道,用户进行频繁的请求时,会一直使用该通道,那么服务器就不需要频繁的建立和关闭。那也有一个坏处就是,假设现在服务器有10万个长连接的请求,那这10万个,所有的用户都需要用到长连接吗,因为连接通道,用户是不会主动关闭的,会一直保持着,直到达到最长连接时间或连接次数,才会关闭,所以,这也会造成资源的浪费,所以,我们在选择长连接的使用的时候,需要根据业务场景来选择,如果用户需要频繁的使用请求,那么就可以选择长连接。
提示:将会持续优化更新
20220730,面试题#13,#14,#15,#16,#17,#18,#19,#20
20220729,面试题#8,#9,#10,#11,#12
20220728,面试题#3,#4,#5,#6,#7
20220727,面试题#1,#2