目录

软件测试经典面试题汇总附答案全网最全,没有之一

目录

软件测试经典面试题汇总附答案全网最全,没有之一

列表式可变的,而元组是不可变化的

列表支持很多内置方法,而元组则很少

列表占用更多的内存,元组内存开销较小

https://i-blog.csdnimg.cn/direct/621ce52a96564b6c87d41b4bb805cc80.png

联系:

生成器是迭代器的子类,因此,生成器是一个迭代器

生成器是创建迭代器的一种简便方式

区别:

迭代器可以通过定义一个类实现,而生成器不需要定义成类

生成器的语法中可以使用yield表达式,但迭代器中不可以

生成器的语法更见简练,而自定义的迭代器类代码较多

https://i-blog.csdnimg.cn/direct/7f44212163f74d2b9821e65b97f41fab.png

python使用了两种内存分配策略:一种是引用统计,另一种是垃圾回收。

引用统计策略是当指向一个对象的引用统计为0,那么对象称之为内存垃圾,所占的内存被立即释放。

垃圾回收策略是通过三代垃圾收集器来跟踪内存中的所有对象。对于每一代,如果对象的数量超过对应的阈值,垃圾收集器将触发回收过程。

python中提供了一些内置的高阶函数,可以很方便的处理数据序列。比如对列表中的所有数据进行运算得到一组新的数据,对序列中的数据进行排序等等。不需要导包,可以直接拿过来使用,常用的有filter, map, sorted等等

pytest fixture是一种@pytest.fixture定义的,通常在具体的测试函数之前或是之后运行的函数

可以使用pytest –fixture查看pytest的所有fixture清单

常用的内置fixture有:

request:用来获取测试函数请求信息

capsys:用来访问被捕获的系统输出

tempdir:用来获取一个临时目录

使用delete语句删除表中的行,如果不指定行可以删除表中的所有数据

使用drop语句可以删除数据库和整个表,包括表结构

使用alter语句可以删除删除表中的列和索引

使用truncate语句可以删除表中的数据,但是会保留表结构

首先我们可以通过ps相关的命令找到该进程的id

使用kill命令杀掉该进程后,就能重新启动新的进程了,可以编写一个脚本把查找进程与杀死进程结合实现便捷杀进程操作

1、http和 htts的区别:

http:超文本传输协议,使用明文发送,80端口

https:安全套接字层超文本传输协议,在http协议的基础上增加了SSL层协议和证书,用来加密传输数据,使用443端口;SSL层协议:security sockets layer安全套接层,是一种安全协议,在传输层对网络进行加密

2、get和post区别:

get:从指定的资源请求数据(从服务器获取数据)

post:向指定的资源提交要被处理的数据(向服务器传送数据)

GET和POST是HTTP协议中的两种发送请求的方法。

HTTP是基于TCP/IP的关于数据如何在万维网中如何通信的协议。

HTTP的底层是TCP/IP。所以GET和POST的底层也是TCP/IP,也就是说,GET/POST都是TCP链接。GET和POST能做的事情是一样一样的。我们要给GET加上request body,给POST带上url参数,技术上是完全行的通的。

在我大万维网世界中,TCP就像汽车,我们用TCP来运输数据,它很可靠,从来不会发生丢件少件的现象。但是如果路上跑的全是看起来一模一样的汽车,那这个世界看起来是一团混乱,送急件的汽车可能被前面满载货物的汽车拦堵在路上,整个交通系统一定会瘫痪。为了避免这种情况发生,交通规则HTTP诞生了。HTTP给汽车运输设定了好几个服务类别,有GET, POST, PUT, DELETE等等,HTTP规定,当执行GET请求的时候,要给汽车贴上GET的标签(也就是设置method为GET),而且要求把传送的数据放在车顶上(url中)以方便记录。如果是POST请求,就要在车上贴上POST的标签,并把货物放在车厢里。当然,你也可以在GET的时候往车厢内偷偷藏点货物,但是这是很不光彩;也可以在POST的时候在车顶上也放一些数据,让人觉得傻乎乎的。HTTP只是个行为准则,而TCP才是GET和POST怎么实现的基本。

但是,我们只看到HTTP对GET和POST参数的传送渠道(url还是requrest body)提出了要求。“标准答案”里关于参数大小的限制又是从哪来的呢?

在我大万维网世界中,还有另一个重要的角色:运输公司。不同的浏览器(发起http请求)和服务器(接受http请求)就是不同的运输公司。 虽然理论上,你可以在车顶上无限的堆货物(url中无限加参数)。但是运输公司可不傻,装货和卸货也是有很大成本的,他们会限制单次运输量来控制风险,数据量太大对浏览器和服务器都是很大负担。业界不成文的规定是,浏览器通常都会限制url长度在2K个字节,而多数服务器最多处理64K大小的url。超过的部分,恕不处理。如果你用GET服务,在request body偷偷藏了数据,不同服务器的处理方式也是不同的,有些服务器会帮你卸货,读出数据,有些服务器直接忽略,所以,虽然GET可以带request body,也不能保证一定能被接收到哦。

好了,现在你知道,GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。

GET和POST还有一个重大区别,简单的说:

GET产生一个TCP数据包;POST产生两个TCP数据包。

长的说:

对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);

而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

也就是说,GET只需要汽车跑一趟就把货送到了,而POST得跑两趟,第一趟,先去和服务器打个招呼“嗨,我等下要送一批货来,你们打开门迎接我”,然后再回头把货送过去。

因为POST需要两步,时间上消耗的要多一点,看起来GET比POST更有效。因此Yahoo团队有推荐用GET替换POST来优化网站性能。但这是一个坑!跳入需谨慎。为什么?

  1. GET与POST都有自己的语义,不能随便混用。
  2. 据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。
  3. 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。

3、Python装饰器原理:

用于拓展原来函数功能的一种函数,整个函数的特殊之处在于,它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数代码的前提下给函数增加新的功能

4、nGrinder工作原理

nGrinder由一个控制端controller和多个代理端agent组成,通过控制端(浏览器访问)建立测试场景,然后分发到代理端进行压力测试。

Controller

提供性能测试的web接口。

协调测试进程。

整理和显示测试的统计结果。

让用户创建和修改脚本。

Agent

在代理服务器上加载运行测试进程和线程

监控目标机器的系统性能(例如:CPU/MEMORY)

当 agent 启动时,它们试图连接到 controller,然后他们都附属在 AgentControllerServer 组件上。

AgentControllerServer (可以看做为一个 agent 的池)管理当前 agent 池。每当用户开始性能测试时,一个新的 console 被创建,同时由 AgentControllerServer 提供所需数量的 agent。

SingleConsole 发送测试脚本和测试源码到多个指定的 agent , 同时开始控制测试流,直到测试结束。当测试完成后,所使用的 agents 归还给 AgentControllerServer ,以便在以后的其他测试中使用。 同样,SingleConsole 也会归还给 ConsoleManager 。

用户按照一定规范编写测试脚本,controller会将脚本以及需要的资源分发到agent,用jython/groovy执行。

在脚本执行的过程中收集运行情况、相应时间、测试目标服务器的运行情况等。并且保存这些数据生成测试报告,通过动态图和数据表的形式展示出来。用户可以方便的看到TPS、被测服务器的CPU和内存等情况。

5、你印象最深的一个bug

之前测试定金预售尾款改版项目的时候出现了一个bug

原来定金预售的流程是用户支付完预付款到了支付尾款的时间直接支付尾款即可

而新的项目将流程修改为用户支付完预付款,到了支付尾款时间,需要将商品进行重新加入购物车,然后走结算下单支付的流程

而出现的问题是:针对套装这种类型的商品,有一个默认选中的逻辑,假设套装C是A商品(白色、黑色)和B商品(黄色、红色)的组合,套装C进入版本选择页面默认选中的是A商品黑色和B商品红色;如果用户支付预付款的时候购买的是A商品白色和B商品黄色,到了支付尾款时间,加入购物车之后的套装版本成了套装C默认选中的版本,也就是用户想买和实际最后加购的不一样了

问题产品的原因就是:尾款加购的时候,应该根据支付预付款订单信息去查询用户购买的商品,然后再让用户去加购,也就是说针对预付款商品,后端尾款加购的时候要查询预付款订单信息;而在测试项目之前,测试也被告知加购的逻辑没有改动,自然也就主要关注了加购之后的结算下单功能

对于测试的思考:

我们测试组当时也进行了内部整体的复盘

1》加强对场景测试用例的设计,以用户的角度多去思考覆盖更多的场景

2》由于单品页套装默认选中项目和改版项目分开来做了,导致该项目整体的衔接位置出了问题,之后会针对大的项目出一个整体的测试负责人,来负责整理的项目流程梳理

  1. DNS解析
  2. TCP链接
  3. 发送HTTP请求
  4. 服务器处理请求并返回HTTP报文
  5. 浏览器解析渲染页面
  6. 链接结束

索引是由表或者视图中的一列或多列生成的键,可以加快在表或者视图中检索行的速度

1、假设A网站是我们要测试的网站,现在A网站打不开了,那么这个时候试试其他一些大的门户网站是否可以打开,如果也是打不开,那么就是测试工程师本机的网络问题,可以联系公司IT人员解决。

2、如果其他网站可以打开,那么就可以判定,应该是被测试网站的问题了,那么这个时候可以通过ping命令,ping网站的域名,如果域名ping不通,那么需要登录到网站的DNS解析的地方,比如阿里云解析,去查看DNS域名解析服务器有没有配置好。

3、如果域名可以ping通,那么这个时候需要登录网站服务器,使用netstat 命令查看80端口有没有启动,如果没有启动,这个时候需要启动80端口后面对应的服务器软件,比如:httpd或者tomcat等。

4、如果80端口处于监听状态的,那么这个时候需要查看服务器的日志文件,进一步从日志上面进行分析。

5、如果日志里面没有看出任何问题,那么这个时候可以联系开发人员,做进一步的代码分析和定位了。

1、需求评审,有可能一次或者多次

2、测试计划、

3、测试用例、

4、用例评审、

5、冒烟测试、

6、测试执行、

7、验收测试、预上线测试

8、风险评估、

9、上线\观察、

10、问题跟进、

11、测试报告、

12、复盘会议;

$ git init

$ git add .

$ git commit

git clone

git add 添加文件到仓库

git status 查看仓库当前的状态,显示有变更的文件。

git diff 比较文件的不同,即暂存区和工作区的差异。

git commit 提交暂存区到本地仓库。

git reset 回退版本。

git rm 删除工作区文件。

git mv 移动或重命名工作区文件。

1.是否面向连接?

TCP通过三次握手,建立连接。

UDP是不用建立连接。

2.是否可靠?

TCP传输的是可靠并有序的数据

UDP只是尽最大努力交付,不一定可靠

3.UDP具有较好的实时性 适用场景:短消息,多客户端,对信息可靠性要求不高,对效率要求高。

4.每一条TCP是点对点的,UDP支持更广泛 一对一,多对一,多对多。

5.TCP对资源要求较高,UDP对资源要求较少。

6.TCP面向数据流, UDP面向数据报。

TCP通过下列方式来提供可靠性:

1、应用数据被分割成TCP认为最适合发送的数据块。这和UDP完全不同,应用程序产生的数据报长度将保持不变。 (将数据截断为合理的长度)

2、当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。 (超时重发)

3、当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒 。 (对于收到的请求,给出确认响应) (之所以推迟,可能是要对包做完整校验)

4、 TCP将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段。 (校验出包有错,丢弃报文段,不给出响应,TCP发送数据端,超时时会重发数据)

5、既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。如果必要,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。 (对失序数据进行重新排序,然后才交给应用层)

6、既然IP数据报会发生重复,TCP的接收端必须丢弃重复的数据。(对于重复数据,能够丢弃重复数据)

7、TCP还能提供流量控制。TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。(TCP可以进行流量控制,防止较快主机致使较慢主机的缓冲区溢出)TCP使用的流量控制协议是可变大小的滑动窗口协议。

字节流服务::两个应用程序通过TCP连接交换8bit字节构成的字节流。TCP不在字节流中插入记录标识符。我们将这称为字节流服务(bytestreamservice)。

TCP对字节流的内容不作任何解释:: TCP对字节流的内容不作任何解释。TCP不知道传输的数据字节流是二进制数据,还是ASCII字符、EBCDIC字符或者其他类型数据。对字节流的解释由TCP连接双方的应用层解释。

接口测试和性能测试

新建一个http请求,右击这个HTTP请求,添加–后置处理器–正则表达式提取器

引用名称:shop_phone 后面接口用到的变量名称

使用正则表达式去匹配这个值

2.新建一个HTTP请求:

引用变量 ${shop_phone}

3.查看结果树 的请求数据,变量值正确

接口测试实际跟一般测试不同就是测试用例的设计部分。

①获取接口规范;

②设计接口测试功能用例(主要从用户角度出发看接口能否实现业务需求);

③各种入参验证(正常情况,异常情况包括输入参数个数不对,类型不对,可选/必选,还 有考虑参数有互斥或关联的情况);

④接口返回值各种验证(符合接口文档需求);

⑤了解接口实现逻辑,实现逻辑覆盖(语句/条件/分支/判定/…);

⑥接口能并发执行吗、安全吗,性能满足要求吗;

⑦采用工具或者自写代码来验证;

⑧发现问题跟功能测试一样,该报 bug 报 bug,该跟踪状态的跟踪状态;

接口测试的质量通常可以通过以下指标进行评估:

1、业务功能覆盖是否完整;

2、业务规则覆盖是否完整;

3、参数验证是否达到要求(边界、业务规则);

4、接口异常场景覆盖是否完整;

5、接口的所有参数是否覆盖

6、接口覆盖率是否达到要求;

7、代码覆盖率是否达到要求;

8、性能指标是否满足要求;

9、安全指标是否满足要求。

HttpClient 是Apache的一个三方网络框架,网络请求做了完善的封装,api众多,用起来比较方便,开发快。实现比较稳定,bug比较少,由于其api众多,是我们很难再不破坏兼容性的情况下对其进行扩展

1.做性能需求分析,挑选了用户使用最频繁的功能来做性能测试,比如:登陆,搜索,提交订单,确定性能指标,比如:事务通过率为100%,90%的事务响应时间不超过5秒,并发用户为1000人,CPU和内存的使用率为70%以下

2.性能测试计划,明确测试时间(通常在功能稳定后,如第一轮测试后进行)和测试环境和测试工具的选择 3.编写性能测试用例

4.搭建性能测试环境,准备好性能测试数据

5.通过性能测试用例,编写性能测试脚本

6.性能测试脚本进行调优,设置检查点、参数化、关联、集合点、事务,调整思考时间,删除冗余的脚本等

7.设计性能测试场景,使用nmon工具监控服务器,运行测试场景

8.分析性能测试结果,如果有问题(性能瓶颈),收集相关的日志提单给开发修改

9.开发修改好后,回归性能测试

10.编写性能测试报告

相关指标:响应时间、并发数、吞吐率、资源利用率、TPS、CPU

负载测试是通过改变系统负载方式、增加负载等来发现系统中所存在的性能问题。负载测试是一种测试方法,可以为性能测试、压力测试所采用。

压力测试通常是在高负载情况下来对系统的稳定性进行测试,更有效地发现系统稳定性的隐患和系统在负载峰值的条件下功能隐患等。

基础监控和应用监控。 基础监控包括机器是否死机,cpu,内存,磁盘使用率等;应用监控包括日志监控、端口监控、进程数监控等。

用过

内存泄漏

1.响应时间(Response Time):t1+t2+t3+t4

time1:客户端——服务器(发送请求)

time2:服务器处理时间

time3:数据库处理时间

time4:服务器——客户端(返回数据)

2.并发\并发数\并发用户数( Concurrent users):一定时间内向服务器发送的请求用户数

a.同一时间在做相同事情的并发(单接口性能测试)

b.同一时间在做不同事情的并发(混合业务场景测试)

所以说,一般先做 单接口的性能测试,然后再做 单业务性能测试,最后做 混合业务场景的性能测试。

3.TPS(Transaction per Second):系统每秒处理的事务数

TPS越高,表示服务器处理能力越好。

QPS:每秒查询数

这也是在做性能测试时,最重要的一个指标值。

4.吞吐量:事务/s,kb/s

在不受网络延迟影响的情况下,吞吐量是和TPS值相等的。

5.资源利用率:主要包括CPU、内存、磁盘、I/O(换入/换出)

一般都要求不会超过80%,占用率越低,表现越好。

我们可以使用pytest_addoption 自定义命令行参数,比如说我们需要在不同的环境中去运行我们的测试用例,那么我们就可以通过命令行去传递不同的环境标识,去得到我们想要的测试结果:

我们在conftest.py文件中编辑这些代码

def pytest_addoption(parser): #parser: 用户命令行参数与ini文件值的解析器

mygroup = parser.getgroup(“learn”) # group 将下面所有的 option都展示在这个group下。

mygroup.addoption(“–env01”, # 注册一个命令行选项

default=‘test’,

dest=‘env01’,

help=‘set your run env’

)

mygroup.addoption(“–env02”, # 注册一个命令行选项

default=‘test’,

dest=‘env02’,

help=‘set your run env’

)

#通过命令行来处理传递不同的参数,设置成fixture,将test环境和dev环境或者其他环境分别处理,获取想要的不同环境下的数据

@pytest.fixture(scope=‘session’)

def cmdoption(request):

myenv = request.config.getoption(“–env”, default=‘test’)

if myenv == ‘test’:

datapath = ‘datas/test/datas.yaml’

好处:防止系统B出错引起测试错误;不会因系统B的开发进度影响测试;mock后可以快速返回结果,提高测试效率。

坏处:很多情况下无法完全模拟出服务器的所有可能的返回情况,另外,mock掉了关联方之后,整个环境的连通性可能测试的不到位

服务器内存不够、服务器超出负载、并发量太大、遇到恶意攻击。

如果应用页面功能分布比较规律比较均匀适合做monkey测试,或者说monkey测试的意义也会更大,而如果自身应用页面结构功能过于简单,或者页面排版过于极端(像我们的功能,主要的页面70%就是文本显示,其他功能按钮什么的隐藏较深很难触发到,容易进去出不来)的,就可以考虑不在monkey测试上投入过多。

使用了命令

adb shell monkey –pct-touch 100 -v -p com.iBer.iBerAppV2 5000 >/Users/kaibinliu/Desktop/monkey_log.txt

1、是否还原设计稿

常见的包括:字体字号、颜色、是否加粗、icon大小、分割线颜色粗细、对齐、间距等。

2、设计细节实现

超出显示:卡片内标题、下拉框选中结果、输入区域超出时是否完整显示(首先要明确显示规则:根据需求不同,有2种规则,超出后…和换行完整显示。)

组件细节:搜索框、较长卡号输入是否有清除按钮

交互流畅:新页面从右侧拉入还是下方进入。

点击区域:保证用户可以点击。

3、是否适配

普通适配:因开发时布局产生的适配问题。多栏按钮适配、非通栏banner适配等。

小屏适配:主要针对iOS。在iPhone6及以上机型可完整显示,iPhone5/SE等小屏显示不完整,需要进行适配处理。

4、核对文案

易错的有:页面标题、空白页、按钮及toast等。

文案的问题,如果团队有专门的测试人员,测试会看的

使用测试用例设计方法设计测试用例

写在yaml文件里面

参数化

接口自动化500多条,通过率99.9%

报告由测试用例执行情况,使用pytest-allure库生成,主要统计成功、失败率,截图和记录日志。

自动化测试主要目的是在于解放测试资源:

1、用更低的人力和设备资源去搭建模拟真实的产品使用场景;

2、用计算机资源去模拟用户,通过脚本去固定的执行一些重复繁琐的操作;

3、打破时间和地点的限制,对产品的运行状况进行24小时监控

自动化适合做为回归测试的主要方式,新上线的功能一般都是用手动测试方式,一些极端和用户习惯操作还是手动测试比较方便。尽可能线上稳定的功能模块都做成自动化,提供效率。

自动化主要作为回归测试,减少测试时间。UI自动化正在进行中 。

核心业务主流程覆盖完全

主要跑的是业务流,所以跑一次需要半个小时左右。

金字塔结构, 最底层UnitTest,往上接口API/集成起来的service, 最上面UI自动化。

提前准备好,在代码里的yaml文件

业务不变的情况下,一般脚本都是不坏不动的。

改造1、搭建PO 模式的架构, 将业务逻辑写出来,后面就不需要改动,除非业务逻辑发生变化

改造 2、填充业务逻辑的实现代码,前端业务流程不变,只变后台逻辑

改造 3、BasePage封装,初始化driver

改造 4、app.py页面, 复用driver ,判断driver是否为None,如果为None 则创建一个Driver, 否则 复用原来的driver self.driver.launch_app()

改造 5、封装 find(), find_and_click(), find_and_sendkeys(), webdriver_wait(), find_byscroll()

改造 6、添加日志便于定位问题

使用yaml文件进行数据驱动测试

1、打印当前手机页面的context

print(driver.contexts)

如果页面中包含H5页面的话,一般至少会返回两个元素,如【native_app,web viewview_com.test.jiayuan】

2、切换到H5页面

driver.switch_to.context(名字)

3、确认是否已经成功切换,打印当前的context

print(driver.current_context)

4、打印当前页面的page_source,并在打印结果中搜索H5页面的文字,如果查的到说明切换成功,否则没成功

优先id,有的name,xpath,classname或者相对定位

takescreen类或者使用webdriver里面的save_screenshot方法

https://i-blog.csdnimg.cn/blog_migrate/c929e2b9e59f4f6ff255792ff5907570.png

使用pytest-xdist库并发执行测试用例

pip install pytest-xdist 分布式并发执行测试用例

测试用例一共有100条,一个执行1分钟,就需要100分钟,如果并行测试10个人一起执行时间就会缩短,这就是一种并行测试,分布式场景;

此方法的应用存在一定的原则,第一,就是用例之间是相互独立的,用例之间没有相互依赖关系,用例可以完全独立运行;第二,用例执行没有顺序,随机顺序都能正常执行;第三,每个测试用例都能重复运行,运行结果不会影响其他测试用例

此应用方式测试用例较多的时候测试效果明显,在执行过程中使用pytest -n 3命令进行执行

方式一:利用jenkins分布式Master-slave来解决,selenium脚本不需要修改,环境部署好,可以直接跑

方式二:利用selenium grid分布式处理,这个有介绍过点击打开链接,剩下就是把selenium grid放到jenkins里面,让jenkins去管理,这个后续一篇介绍,这种方式,driver的url要改成hud的,脚本需要稍加修改

使用execute_script方法

ele = self.driver.execute_script(“return document.getElementById(‘su’)”).click()

self.driver.execute_script(“document.documentElement.scrollTop=10000”)

xpath\name\id\相对定位

Appium是 c/s模式的

appium是基于 webdriver 协议添加对移动设备自化api扩展而成的

webdriver 是基于 http协议的,第一连接会建立个 session 会话,并通过 post发送一个 json 告知服务端相关测试信息

Appium通信原理:Client端发送自动化指令给Appium server,Appium Server接收到client发送的指令后,转换为移动端能够识别的指令,然后发送给移动端设备,并对移动端设备进行操作。

Appium使用WebDriver的json wire协议,来驱动Apple系统的UIAutomation库、Android系统的UIAutomator框架

appium ios自动化的底层使用的是UI Automation,因此在使用appium之前必须搭建IOS开发环境。

80%是你元素定位的不对

那么多定位方法,一个不行换另外一个

直接不能定位,先定位父元素,再循环找子元素。

一般来说XPATH都能定位到,无非是可阅读性不强。

真的全部失效,请求开发帮你改个元素属性好了。

UI测试给予下面三个类的实现:

XCUIApplication

XCUIElement

XCUIElementQuery

driver.find_element_by_accessibility_id(‘搜索或输入网址’)

需要改端口,多个端口

然后在caps文件中获取多设备

from selnium import webdriver

1.selenium client(python等语言编写的自动化测试脚本)初始化一个service服务,通过Webdriver启动浏览器驱动程序chromedriver.exe

2.通过RemoteWebDriver向浏览器驱动程序发送HTTP请求,浏览器驱动程序解析请求,打开浏览器,并获得sessionid,如果再次对浏览器操作需携带此id

3.打开浏览器,绑定特定的端口,把启动后的浏览器作为webdriver的remote server

3.打开浏览器后,所有的selenium的操作(访问地址,查找元素等)均通过RemoteConnection链接到remote server,然后使用execute方法调用_request方法通过urlib3向remote server发送请求

4.浏览器通过请求的内容执行对应动作

5.浏览器再把执行的动作结果通过浏览器驱动程序返回给测试脚本

id name class 相对定位 contains

第一种xhr提交

第二种jQuery的ajax提交

第三种就是利用ifram来进行上传文件

找父级元素,通过父级元素查找子元素,xpath

先使用一个文件实现一个主流程

然后对其进行封装

公共的方法代表页面提供的服务

不需要暴露页面的交互细节

通常来说不要做断言

方法返回其他PO

不需要代表整个页面

相同的行为导致的不同结果,封装成不同的方法

pytest第三方插件pytest-html,新建一个关于截图的插件文件conftest.py

pytest –collect-only 只收集测试用例

pytest -m mark 标签名 标记

pytest [测试文件] -s -q –alluredir=./resullt/(–alluredir这个选项用于指定存储测试结果的路径)

查看报告

allure serve ./result/

pytest test_a.py -m “case_b” -vs只运行case_b标签的测试用例

tail -f

find user -size +5000k -type f

ps -ef

find . -name ‘*.exe’ -type f -exec rm -rf { }

cat /proc/cpuinfo查看linux系统的CPU型号、类型以及大小

通过greap命令根据Physical Processor ID筛选出多核CPU的信息

cat /proc/meminfo查看linux系统内存大小的详细信息,可以查看总内存,剩余内存、可使用内存等信息。

df -h查看linux系统各分区的使用情况

free -m 查看linux系统内存使用量和交换区使用量

如果log文件是这样的:

10.202.134.114 - - [26/Jun/2019:19:20:29 +08:00] “GET /product/list?count=1000&page=1&r=1561548021&ver=1.0 HTTP/1.1” 203 95458 “-” “-” 223 8.624 8.624 127.0.0.1:8800

10.202.134.114 - - [26/Jun/2019:19:20:29 +08:00] “GET /product/list?count=1000&page=1&r=1561548021&ver=1.0 HTTP/1.1” 201 95458 “-” “-” 223 8.624 8.624 127.0.0.1:8800

10.202.134.114 - - [26/Jun/2019:19:20:29 +08:00] “GET /product/list?count=1000&page=1&r=1561548021&ver=1.0 HTTP/1.1” 200 95458 “-” “-” 223 4.56 8.624 127.0.0.1:8800

10.202.134.114 - - [26/Jun/2019:19:20:29 +08:00] “GET /product/list?count=1000&page=1&r=1561548021&ver=1.0 HTTP/1.1” 200 95458 “-” “-” 223 8.624 8.624 127.0.0.1:8800

shell脚本:

awk -F ’ ’ ‘BEGIN{i=0;j=0}{if($9==200){i+=1;print $14;j+=$14}}END{print i;print j/i}’ ~/nginx.log

思路:

1、使用空格作为分割符,确认第几个字段是状态码;根据Nginx的配置,确认第几个字段是request_time

2、awk的工作原理:awk ‘BEGIN{}{}END{}’

面向对象编程就是把具有共性的事务抽象成属性和方法来进行编程。

有三个线程T1,T2,T3,怎么确保它们按顺序执行?————在多线程中有多种方法让线程按特定顺序执行,你可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。

start 启动时用的,只调用一次

run 可以调用多次

import threading

"""
线程安全的单利模式

紧跟with后面的语句被求值后,返回对象的 __enter__() 方法被调用,这个方法的返回值将被赋值给as后面的变量。
当with后面的代码块全部被执行完之后,将调用前面返回对象的 __exit__()方法
"""
def synchronized(func):
    func.__lock__ = threading.Lock()

    def lock_func(*args, **kwargs):
        with func.__lock__:
            return func(*args, **kwargs)

    return lock_func

class Singleton(object):
    instance = None

    @synchronized
    def __new__(cls):
        # 关键在于这,每一次实例化的时候,我们都只会返回这同一个instance对象
        if not cls.instance:
            cls.instance = super(Singleton, cls).__new__(cls)
        return cls.instance
#冒泡排序:n*n
def bubbleSort(array):
  maxindex = len(array)-1
  maxValue = array[maxindex]
  k=0
  while maxindex:
      for i in range(1,maxindex):
          if array[i-1]>array[i]:
              temp = array[i]
              array[i] = array[i-1]
              array[i-1] = temp
          k+=1
      maxindex -=1
  print(k)
  return array
def count_digit(number):
    return len(str(number))

def countThree(digit):
    if not isinstance(digit,int):
        raise TypeError('number is not int')
    # digit = len(str(number))
    if(digit <=0):
        return 0
    if(digit ==1):
        return 1
    return 10*countThree(digit-1) + 10 **(digit-1)

print(countThree(count_digit(9999)))
#快速排序:最快的n*logN
def qiuckSort(list):
    if len(list)<2:
        return list
    mid = list[0]
    left = [i for i in list[1:] if i <= mid]
    right = [i for i in list[1:] if i > mid]
    finallyList = qiuckSort(left)+[mid] + qiuckSort(right)
    return finallyList
array = [3, 0, 1, 832,23,45, 5, 5, 6,46, 9, 56, 897]
print(qiuckSort(array)[-4:])

原理遍历删除即可

判断一个字符串是否为空,首先就要确保他不是null,然后再判断他的长度

原理:个位乘以1,十位乘以10,百位乘以100.。。

具体思路如下:首先自己调用链表的创建函数,手动创建两个有序链表,链表的创建以输入0作为截止标志。创建好两个有序链表之后,将两个链表的头结点进行比较,小的那个作为合并后的链表的头结点,同时,创建两个指针分别指向两个链表的的头结点或头结点的下一个节点,当两个链表进行比较的元素都不为空的话,依次从小到大连接,若有一个链表中比较的节点开始为空时,则将另一个链表的剩余节点添加到合并链表的末尾。

去重,把临近的一组去掉,在递归调用比较去重直到最后,如果有剩下则不返回false;否则true;

def sum_str(a: str, b: str) -> str:
    max_str, min_str = (a, b) if len(a) > len(b) else (b, a)
    c = 0
    tmp_num = False
    for i in range(len(min_str)):
        d = int(max_str[-(i + 1)]) + int(min_str[-(i + 1)])
        d = d + 1 if tmp_num else d
        tmp_num = False
        if d > 10:
            tmp_num = True
        c += d if i == 0 else d * 10 ** i
    for i in range(len(min_str), len(max_str)):
        if tmp_num:
            c += int((max_str[-(i + 1)] + 1)) * 10 ** i
            tmp_num = False
        c += int(max_str[-(i + 1)]) * 10 ** i
    return c

算法原理:

把一亿个数字的前100个 首先放入数组。 然后把最小值放在ary[0]。

然后再,循环100到一亿 之间的。 每次循环判断当前数字是否大于ary[0]

当大于时,当前数字放入ary[0] 并再次重构数组最小值进入ary[0] 以此类推 。

当循环完这一亿个数字后。 最大的前100个数字就出来了。

左外连接:将左表为驱动表进行连接,结果数据包含左表全部数据,以及右表中和左表匹配的数据,左表中有,但右表中没有的数据显示null(取左边全部及右边部分数据)

SELECT * FROM TABLE1 LEFT JOIN TABLE2 ON TABLE1.USERNAME=TABLE2.USERNAME

右外连接:将右表为驱动表进行连接,结果数据包含右表全部数据,以及左表中和右表匹配的数据,右表中有,但左表中没有的数据显示null(取右边全部及左边部分数据)

SELECT * FROM TABLE1 RIGHT JOIN TABLE2 ON TABLE1.USERNAME=TABLE2.USERNAME

内连接:等值连接,返回两张表中都满足匹配条件的数据 (取两个表的交集)

SELECT * FROM TABLE1 INNER JOIN TABLE2 ON TABLE1.USERNAME = TABLE2.USERNAME

SELECT * FROM TABLE1 JOIN TABLE2 ON TABLE1.USERNAME=TABLE2.USERNAME

create table myTestTable as

select rownum as id,

to_char(sysdate + rownum/24/3600, ‘yyyy-mm-dd hh24:mi:ss’) as inc_datetime,

trunc(dbms_random.value(0, 100)) as random_id,

dbms_random.string(‘x’, 20) random_string

from dual

connect by level <= 100000;

将数据写在yaml文件,读取yaml文件内容驱动测试

当赋值列表、键值对时,转换成Python数据结构是可以直接当列表、字典使用的;、

当赋值元组时,转换后也是字符串

最终输出的都是字典类型,可以通过key获取对应的值

1.是否面向连接?

TCP通过三次握手,建立连接。

UDP是不用建立连接。

2.是否可靠?

TCP传输的是可靠并有序的数据

UDP只是尽最大努力交付,不一定可靠

3.UDP具有较好的实时性 适用场景:短消息,多客户端,对信息可靠性要求不高,对效率要求高。

4.每一条TCP是点对点的,UDP支持更广泛 一对一,多对一,多对多。

5.TCP对资源要求较高,UDP对资源要求较少。

6.TCP面向数据流, UDP面向数据报。

为了保证数据能到达目标,TCP采用三次握手策略:

发送端首先发送一个带SYN(synchronize)标志的数据包给接收方【第一次的seq序列号是随机产生的,这样是为了网络安全,如果不是随机产生初始序列号,黑客将会以很容易的方式获取到你与其他主机之间的初始化序列号,并且伪造序列号进行攻击】

接收端收到后,回传一个带有SYN/ACK(acknowledgement)标志的数据包以示传达确认信息【SYN 是为了告诉发送端,发送方到接收方的通道没问题;ACK 用来验证接收方到发送方的通道没问题】

最后,发送端再回传一个带ACK标志的数据包,代表握手结束若在握手某个过程中某个阶段莫名中断,TCP协议会再次以相同的顺序发送相同的数据包Q

为什么要三次握手?

三次握手的目的是建立可靠的通信信道,说到通讯,简单来说就是数据的发送与接收,而三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的

第一次握手,发送端:什么都确认不了;接收端:对方发送正常,自己接受正常

第二次握手,发送端:对方发送,接受正常,自己发送,接受正常 ;接收端:对方发送正常,自己接受正常

第三次握手,发送端:对方发送,接受正常,自己发送,接受正常;接收端:对方发送,接受正常,自己发送,接受正常

TCP四次挥手:

主动断开方(客户端/服务端)-发送一个 FIN,用来关闭主动断开方(客户端/服务端)到被动断开方(客户端/服务端)的数据传送

被动断开方(客户端/服务端)-收到这个 FIN,它发回一 个 ACK,确认序号为收到的序号加1 。和 SYN 一样,一个 FIN 将占用一个序号

被动断开方(客户端/服务端)-关闭与主动断开方(客户端/服务端)的连接,发送一个FIN给主动断开方(客户端/服务端)

主动断开方(客户端/服务端)-发回 ACK 报文确认,并将确认序号设置为收到序号加1

为什么连接的时候是三次握手,关闭的时候却是四次握手?

建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以服务器可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接。因此,服务器ACK和FIN一般都会分开发送,从而导致多了一次。

TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭

服务器A是一台爬虫服务器,它使用简单的HttpClient去请求资源服务器B上面的apache获取文件资源,正常情况下,如果请求成功,那么在抓取完 资源后,服务器A会主动发出关闭连接的请求,这个时候就是主动关闭连接,服务器A的连接状态我们可以看到是TIME_WAIT。如果一旦发生异常呢?假设 请求的资源服务器B上并不存在,那么这个时候就会由服务器B发出关闭连接的请求,服务器A就是被动的关闭了连接,如果服务器A被动关闭连接之后程序员忘了 让HttpClient释放连接,那就会造成CLOSE_WAIT的状态了。

所以如果将大量CLOSE_WAIT的解决办法总结为一句话那就是:查代码。因为问题出在服务器程序里头啊。

一个端到端的测试web工具

速度感觉上比 selenium 要快。

内置的 request 方法可以直接跳过 UI 层的登录,但要求是你能调用对应的登录接口。

某些步骤运行失败时自动重试。这样可以提高运行的稳定性。

运行失败时自动截图。

然后我们新建一个001的collection,然后将该接口保存到这个collection里面

点击001旁边的小箭头

点击run,会出来一个弹窗

选择test.txt文件,以及对应的文件格式,iterations迭代次数3次

点击run001

我们可以通过环境变量和全局变量设置参数关联,当然也可以通过tests设置进行参数关联

假设我们有三个接口,一个是加自选的接口,一个是取消加自选的接口,一个是查看自选的list,我们首先把某米集团加入自选,然后请求自选list,然后取消已经加自选成功的某米集团,因此,为了取消加自选成功的某米集团,我们需要在list接口中获取到已经加购成功的小米集团的symbol字段的值,也就是说我们可以在tests中使用symbol进行关联,首先我们在list接口中填写以下内容,用来获取环境变量:

//获取响应数据的json对象

var Data = pm.response.json();

//从响应数据中提取business_id

var symbol = Data.data.stocks[0].symbol

//设置business_id

pm.environment.set(“symbols”, symbol)

top显示所有正在运行而且处于活动状态的实时进程

netstat用于监控进出网络的包和网络接口统计的命令行工具,非常有用,用来监控网络性能

ping 将数据包发向用户指定地址

ifconfig查看用户网络配置

tcpdump用于捕捉或过滤网络上指定接口上接收或者传输的TCP/IP包

第1步:熟悉产品

第2步:压测工具

第3步:测试数据构造

第4步:性能环境部署

第5步:性能监控

性能脚本准备好了

示例:

假设 words.txt 内容如下:

the day is sunny the the

the sunny is is

你的脚本应当输出(以词频降序排列):

the 4

is 3

sunny 2

day 1

# Read from the file words.txt and output the word frequency list to stdout.
cat words.txt | tr -s ' ' '\n' | sort | uniq -c | sort -r | awk '{print $2" "$1}' 

tr -s ’ ’ ‘\n’ 表示的是空格替换换行

sort表示的是以行为单位对文本进行排序

uniq -c表示的是

sort -r表示的是按照反向输出排序结果,也就是从大到小

你可以假设一个有效的电话号码必须满足以下两种格式: (xxx) xxx-xxxx 或 xxx-xxx-xxxx。(x 表示一个数字)

你也可以假设每行前后没有多余的空格字符。

示例:

假设 file.txt 内容如下:

987-123-4567

123 456 7890

(123) 456-7890

你的脚本应当输出下列有效的电话号码:

987-123-4567

(123) 456-7890

# Read from the file file.txt and output all valid phone numbers to stdout.
grep -P '^(\d{3}-|\(\d{3}\) )\d{3}-\d{4}$' file.txt  

注意中间空格

95、给定一个文件 file.txt,转置它的内容。

你可以假设每行列数相同,并且每个字段由 ’ ’ 分隔。

示例:

假设 file.txt 文件内容如下:

name age

alice 21

ryan 30

应当输出:

name alice ryan

age 21 30

awk '{ #这个大括号里的代码是 对正文的处理
    # NF表示列数,NR表示已读的行数
    # 注意for中的i从1开始,i前没有类型
    for (i=1; i<=NF; i++){#对每一列
        if(NR==1){       #如果是第一行
            #将第i列的值存入res[i],$i表示第i列的值,i为数组的下标,以列序号为下标,
            #数组不用定义可以直接使用
            res[i]=$i;   
        }
        else{
            #不是第一行时,将该行对应i列的值拼接到res[i]
            res[i]=res[i] " " $i
        }
    }
}
# BEGIN{} 文件进行扫描前要执行的操作;END{} 文件扫描结束后要执行的操作。
END{
    #输出数组
	for (i=1; i<=NF; i++){
		print res[i]
	}
}' file.txt
awk 'NR==10' file.txt
class Solution:
    def rob(self, nums):
        length = len(nums)
        if length == 0:
            return 0
        if length == 1:
            return nums[0]
        left, right = nums[0],max(nums[0], nums[1])
        for i in range(2, length):
            left,right = right,max(left + nums[i], right)
        return right
  1. 根据需求说明书编写测试计划;
  2. 制定测试方案,主要是测试任务、测试人员和测试时间的分配;
  3. 测试准备,包括搭建测试环境,准备测试数据,确定测试方法;
  4. 测试用例的设计与编写,进行用例评审及补充完善;
  5. 执行测试时首先进行冒烟测试,然后对主功能流程进行测试,包括客户端的单个功能模块,及功能业务逻辑功能交互,回归测试;
  6. 提交测试结果,包括测试用例,测试计划;
  7. 日常维护性测试;

具体要准备的测试资源,根据实际项目来,可以从以下几个方面出发:

1.IOS设备、Android设备(选取市面上主流手机产品);

2.支付宝/银联支付的项目,需要提前申请支付宝/银联账户等等;

3.有秒杀专题的题目,需要规划秒杀时间表;

4.有优惠券使用的项目,需要添加优惠券数据;

1.两者运行机制不同:IOS采用的是沙盒运行机制,安卓采用的是虚拟机运行机制。

IOS 沙盒运行机制:

每个程序都有自己的虚拟地址空间。所以,程序之间不能进行访问。

默认只会将应用的最后运行数据,记录在RAM里面。

Android 虚拟机运行机制:

所有的应用程序都是运行在虚拟机中,用户界面其实是由虚拟机传递的,并且通过虚拟机,Android的任何程序都就可以轻松访问其他程序文件。

所有的Android的应用程序都是运行在RAM里面的,所以会发现有时候Android用着用着就开始有点卡顿。

2.两者后台制度不同:IOS中任何第三方程序都不能在后台运行;安卓中任何程序都能在后台运行,直到没有内存才会关闭。

3.IOS中用于UI指令权限最高,安卓中数据处理指令权限最高。

ADB作为一个客户端/服务器架构的命令行工具,主要由3个部分组成。

adb clent(客户端):可以通过它对Android应用进行安装、卸载及调试。

adb service(服务器):管理客户端到Android设备上abd后台进程的连接,负责管理client和damon进行通信。

adb daemon(守护进程):运行在Android设备上的adb后台进程。

Android四大基本组件:Activity、BroadcastReceiver广播接收器、ContentProvider内容提供者、Service服务。

Activity:应用程序中,一个Activity就相当于手机屏幕,它是一种可以包含用户界面的组件,主要用于和用户进行交互。一个应用程序可以包含许多活动,比如事件的点击,一般都会触发一个新的Activity。

BroadcastReceiver广播接收器:应用可以使用它对外部事件进行过滤只对感兴趣的外部事件(如当电话呼入时,或者数据网络可用时)进行接收并做出响应。广播接收器没有用户界面。然而,它们可以启动一个activity或serice 来响应它们收到的信息,或者用NotificationManager来通知用户。通知可以用很多种方式来吸引用户的注意力──闪动背灯、震动、播放声音等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。

ContentProvider内容提供者:内容提供者主要用于在不同应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性。只有需要在多个应用程序间共享数据时才需要内容提供者。例如:通讯录数据被多个应用程序使用,且必须存储在一个内容提供者中。它的好处:统一数据访问方式。

Service服务:是Android中实现程序后台运行的解决方案,它非常适合去执行那些不需要和用户交互而且还要长期运行的任务(一边打电话,后台挂着QQ)。服务的运行不依赖于任何用户界面,即使程序被切换到后台,或者用户打开了另一个应用程序,服务仍然能够保持正常运行,不过服务并不是运行在一个独立的进程当中,而是依赖于创建服务时所在的应用程序进程。当某个应用程序进程被杀掉后,所有依赖于该进程的服务也会停止运行(正在听音乐,然后把音乐程序退出)。

生命周期即活动从开始到结束所经历的各种状态,从一个状态到另一个状态的转变,从无到有再到无,Activity本质上有四种状态:

运行(Active/Running):Activity处于活动状态,此时Activity处于栈顶,是可见状态,可以与用户进行交互。

暂停(Paused):当Activity失去焦点时,或被一个新的非全面屏的Activity,或被一个透明的Activity放置在栈顶时,Activity就转化为Paused状态。此刻并不会被销毁,只是失去了与用户交互的能力,其所有的状态信息及其成员变量都还在,只有在系统内存紧张的情况下,才有可能被系统回收掉。

停止(Stopped):当Activity被系统完全覆盖时,被覆盖的Activity就会进入Stopped状态,此时已不在可见,但是资源还是没有被收回。

系统回收(Killed):当Activity被系统回收掉,Activity就处于Killed状态。

如果一个活动在处于停止或者暂停的状态下,系统内存缺乏时会将其结束(finish)或者杀死(kill)。这种非正常情况下,系统在杀死或者结束之前会调用onSaveInstance()方法来保存信息,同时,当Activity被移动到前台时,重新启动该Activity并调用onRestoreInstance()方法加载保留的信息,以保持原有的状态。

在上面的四中常有的状态之间,还有着其他的生命周期来作为不同状态之间的过渡,用于在不同的状态之间进行转换。

有如下几个工具:

ddms:Dalvik Debug Monitor Service,是 Android 开发环境中的Dalvik[虚拟机]调试监控服务。

monkey:Android中的一个命令行工具,可以运行在模拟器里或实际设备中。它向系统发送伪随机的用户事件流(如按键输入、触摸屏输入、手势输入等),实现对正在开发的应用程序进行压力测试。

uiautomator:UIAutomator是Eclipse自带的用于UI自动化测试工具,可仿真APP上的单击、滑动、输入文本等操作。

monitor:同uiautomator

adb:ADB的全称为Android Debug Bridge,就是起到调试桥的作用。通过ADB我们可以在Eclipse中方面通过DDMS来调试Android程序,就是debug工具。

常用的APP测试工具如下:

APP自动化测试工具:

Appium

Airtest

uiautomator2(python)

APP稳定性测试工具:

Monkey

MonkeyRunner

Maxim

UICrawler

APP性能测试工具:

GT

Perfdog

SoloPi

APP弱网测试&抓包工具:

QNET

Fiddler

Charles

APP兼容性测试工具:

TestIn

腾讯优测

百度MTC

阿里MQC

APP安全测试工具:

OWASP ZAP

Drozer

MobSF

QARK

APP启动会发生多个事件,测试人员需要知道整个环节是否出现问题,需要了解到具体是哪个环节存在问题:

冷启动:当进程不存在的时候,从进程创建开始到界面的展示的过程;

暖启动:有一部分资源已经存在,进程存在,相对于热启动要消耗更多资源。当用户退出应用程序时,进程还会存在,暖启动相较于冷启动只是少了进程的创建;

热启动:大部分资源都在,只是应用之间的切换;

首屏启动:第一屏加载完整;

标准:

冷启动:需要5秒甚至更长;

暖启动:需要2秒甚至更长;

热启动:需要1.5秒甚至更长;

整个启动过程可以用adb工具进行分析,利用adb logcat获取启动数据,或者录屏,使用ffmpeg拆帧分析。

应用的启动可以分为冷启动,热启动和温启动,而启动最慢、耗时最长的就是冷启动。

冷启动开始时,系统会依次执行三个任务去启动APP:

  1. 加载和启动应用程序;
  2. APP启动后,立即创建一个空白的启动Window;
  3. 创建APP的进程;

在这三个任务执行后,系统创建了应用进程,那么应用进程接下来会执行下一步:

  1. 创建APP对象;

  2. 开启一个主线程;

  3. 创建启动页的Activity;

  4. 加载View;

  5. 布局view到屏幕;

  6. 进行初始绘制显示视图;

    当应用进程完成初始绘制之后,系统进程用启动页的Activity来替换当前显示的空白Window,这个时刻用户就可以使用App了。

只有xpath可以通过子元素定位父元素,两个点表示定位当前元素的父元素

1、都是数据结构,都可以用数组、链表实现

2、栈的特性是后进者先出,先进着后出;队列的特性是后进先出

3、栈只允许在一端插入和删除数据;队列可以在队首队尾进行运算

linux系统

首先,我们可以通过ps或者netstate的相关命令找到tomcat进程的id,使用KILL命令杀掉该进程后,就能重新启用一个新的进程了,可以编写一个脚本把查找进程与杀死进程结合实现便捷

windows系统

首先通过netstate找到tomcat进程的pid,通过task kill把找到的pid杀掉

通过查看当面页面的dom,搜索该元素是否存在。如果是脚本自动化运行过程中,应该通过打印page_source,即可了解到该元素在运行过程中是否存在

原因是异步加载js导致点击不到,解决方案就是循环点击该按钮,直到生效为止

隐藏元素可以直接定位,但是无法直接点击或者交互,可以使用js执行交互操作

toast闪过太快,不好定位,解决方案就是直接通过xpath定位结合隐式等待获取

通过添加黑名单异常处理解决

定位错误

解决方案:在console先测试定位是否正确

页面还没有加载完成

解决方案:添加死等验证,使用显示等待或隐式等待进行优化

存在动态ID

解决方案:定位方式使用CSS或者xpath的相对定位

页面有iframe

解决方案:切换到iframe后定位

页面切换window

解决方案:切换到对应窗口后定位

类型使用方式原理
直接等待time.sleep()强制线程等待
隐式等待driver.implicity_wait()在时间范围内,轮询查找元素
显示等待WebDriverWait(driver实例,最长等待时间).until(条件函数)设定特定的等待条件,轮询操作

header命令可以实现,header -10

使用int()函数接收字符串,返回整数

字符串的值必须是数值形式,否则会报ValueError

平时工作中使用最多的是pytest单测框架,进行自动化测试用例的管理

使用pytest自带的装饰器parametrize可以实现参数化

等价类划分法

边界值分析法

因果图法

判定表法

场景分析法

错误推断法

1、如果函数需要支持传入可变参数,前提是将函数的形参前面加上一个或两个星号

2、可变的位置参数通常使用 * args表示,调用时按照位置传入实参即可,所有接收到的实参会被收集成一个元组对象

3、可变的关键字参数通常使用**kwargs表示,调用时按照key=value的格式传入实参即可,所有接收到的实参会被收集成一个字典对象

1、json是一种用于在系统应用之间进行数据传输的文本格式,而python语言中的dict是一种内存中数据结构

2、由于json的内容是文本,因此在其中查找一个key的时间复杂度是O(n),而dict使用哈希值,时间复杂度是O(1),所以查找键的效率比json高效很多

3、json的键仅支持字符串格式,必须是双引号包围;而dict的键支持任何可哈希的对象作为键,包括元组,自定义类等等

4、json的值的要求是有效的json类型,包括数组、对象、字符串、浮点数、布尔值和null。而dict字典的值可以是python中任何数据类型,包括整数、浮点数、列表、元组等等

列表是可变的,而元组是不可变的

列表支持很多内置方法,而元组则较少

列表占用更多的内存,元组内存开销较小

HTTPS是安全套接字层超文本传输协议。因为HTTP协议使用明文发送内容,安全性很差,为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL/TLS安全层,让传输的安全性大大提高。

SSL/TLS协议是HTTP与TCP之间的安全协议,可以验证服务器的身份,为客户端和服务端之间的通信加密,并且保证信息的完整性。

SSL是安全套接层。后来SSL被标准化。标准化之后的名称改为TLS传输层安全协议。所以这两者其实就是同一种协议,只不过是在不同阶段的不同称呼。

is是比较两个对象的内存地址是否相等

==是比较两个对象的内容是否相等

id()可以查看对象的内存地址

首先我们可以通过tail或者less命令打开日志

打开日志的时候配合参数tail结合-f,less打开的日志后使用shift+f实现日志的实时查看

https://i-blog.csdnimg.cn/direct/327426485f31478c85ed739b7267844c.png