第一次面试:tuzhan
你的自动化脚本是怎么写的
- 我写自动化主要实现的功能是不同并数进行自动化测试
- 我就把shell脚本实现的逻辑讲了,定义一个jmx的模板文件,写一个傻掉jmeter进程的函数,通过awk,grep获取特定的jmeter的pid,用kill pid删掉,作用是假设你要运行60秒,但可能jmeter60秒后还有些请求需要发送,来不及发送出现卡顿,避免下次重复执行jmeter压测
- 接下来定义一个并发数的数组,用for循环拿到数组的值,比如第一次循环拿到100,定义新的jmx文件,名字加上100,定义新的jtl文件,名字加上100,复制jmx的模板到新的jmx文件,当心的jmx运行完毕之后,就可以删除jmx文件,模板的jmx可以不用删除。我们的jmx文件是先删除,后复制,因为可能之前运行了,没有删除
- 用nohup &后台运行jmeter,配上jmx和jtl,sleep时间比运行之间长一点,运行结束后杀掉进程
- 最终脚本运行完毕后,只会留下jtl的报告,用jmeter打开就可以获取不同并发下的数据了
你对性能测试了解有多少
- 讲了一下参数化,接口参数传递,聚合报告主要的指标,顺带提了一下可以结合influxdb grafana设计一个测试环境的接口监控。目的是为了及时发现开发接口可能发生的拓展和更新。性能深层次的不太了解,因为项目不太需要
你所写的自动化性能测试的脚本,仅仅是自动跑不同的并发数,我用一个jmeter的一个插件就可以实现
- 的确可以通过插件的方式实现不同并发量的测试,但是聚合函数记录的是一个总的数据,假设并发数是100,200,300,只能记录三者共同的响应时间、错误率、吞吐量(Throughput),无法记录单独并发的聚合报告的数据
- 想要解决这个问题可以搭建influxdb+grafana环境,我们只需要选取我们测试的时间段,就可以记录不同并发独自的数据了
- 我之所以会写这个脚本,是因为我的电脑使用这个插件有些问题,并发数设置的数量并不对
jmeter聚合报告的流量是怎么计算的
- 这个是叫吞吐量(throughput),是每秒完成的请求数
- 计算的公式有两个:
- 吞吐量=并发数/请求的平均响应时间s,例子:假设有10个并发,请求响应时间是47ms,TPS=10/(47/1000)
- 吞吐量=总的请求数量/总的请求时间,例子:
加密方式有哪些
- 普通的加密:base64
- 不可逆的加密方式:MD5,sha1,sha1安全性高,速度慢
- 有对称式加密:DES,AES
- 非对称式加密:RSA
http的无状态是什么意思
- 每一次请求之间是没有关联的,比如我登录了之后,给服务器发送了账户名和密码,返回了登录的界面,下次我想再请求登录后的界面,服务器就不认识我了,因为服务器不知道客户端是谁,客户端没有携带任何信息证明自己
cookies和session的区别是什么
- cookies是保存在客户端的,session是保存在服务器端的,当我们登录了之后,服务器会把session-id给到客户端的cookies中。当客户端再发送请求,客户端就在cookies中携带这个session-id给到服务器
- session-id如果存在redis中,key通过是固定死的,比如就叫session-id,服务器就拿session-id的value进行检验比对,识别到客户端的身份
那服务器是怎么比对session-id的
- session-id如果存在redis中,key通过是固定死的,比如就叫session-id,服务器就拿session-id的value进行检验比对,识别到客户端的身份
cookies里面有什么内容
- 有session-id,识别用户身份
- 有token,识别用户身份
- 有Domain:域,cookies在哪个域名下有作用
- 有Path,表示哪些路径下的目录有权限读取
- 有Expire time有效期时间
- secure,表示必须用https传输的cookies才有效
- 有http only,只允许http和https传输,无法使用js脚本,防止xss跨脚本攻击
- 反射型XSS,通过邮件或者其他方式,给用户链接,用户点击链接后,就会自动运行链接的js脚本,达到获取cookies或者其他攻击
- 存储型xss,用于论坛,博客,黑客把js代码直接留言到论坛或者博客,可以保存这些js代码到数据库,当其他用户访问论坛,浏览器就会自动读取当前页面的js代码,实现攻击
如何判断跨域,cookies跨域是怎么处理的
- 通过cookies的domain的域设置来判断的,如果www.baidu.com的domain设置为www.baidu.com,那么只能访问www.baidu.com或者更高的域名,无法访问tieba.baidu.com,或者是www.qq.com,因为跨域了
- 想要访问tieba.baidu.com,domain可以设置成baidu.com,更上级的www和tieba也可以访问了
如何对一个{“name”:“age”}的字典去进行排序
def test_a():
name={"abc":200,"aaa":19,"bbb":30,"ddd":25,"qec":100}
print(len(name))
result=[]
for i in range(len(name)):
new_age=0
new_name=""
for b,a in name.items():
if a>new_age:
a,new_age=new_age,a
new_name=b
# else:
# a,new_age=a,new_age
result.append((new_age,new_name))
name.pop(new_name)
print(result)
#对key进行排序
def test_b():
name={"abc":200,"aaa":19,"bbb":30,"ddd":25,"qec":100}
for i in sorted(name):
print(f"{i},{name[i]}")
#对value进行排序
def test_b():
name={"abc":200,"aaa":19,"bbb":30,"ddd":25,"qec":100}
print(name.items())
#从大到小进行排序
a=sorted(name.items(),key=lambda x:x[1])
print(a)
#从小到大进行排序
b=sorted(name.items(),key=lambda x:x[1],reverse=True)
#对key进行排序
def test_b():
name={10:200,"aaa":19,"bbb":30,"ddd":25,"qec":100}
print(name.items())
#从大到小进行排序
a=sorted(name.items(),key=lambda x:x[0])
print(a)
#从小到大进行排序
b=sorted(name.items(),key=lambda x:x[0],reverse=True)
def test_c():
a=[5,9,30,20,60,9,7,100]
new=0
for i in range(len(a)-1):
for j in range(len(a)-1-i):
if a[j]>a[j+1]:
a[j+1],a[j]=a[j],a[j+1]
print(a)
token有什么作用
- token是令牌,做认证的,可以替代session-id,session-id存在会给服务器带来存储的压力,例如如果你的用户数是亿级的,压力非常大
- token可以解决这个问题,服务器不去存储token,当客户端把账号密码提供后,服务器就会根据服务器和密码和过期时间做一个加密,形成一个token发给服务器,服务器如果收到了这个token,就会进行解密,可以获取用户名,密码和过期时间,来识别身份
- token可以防止表单的重复提交,原理不懂
- token还可以防止CSRF跨站请求伪造
- CSRF的攻击是用户登录了一个银行网站,保存了cookies,当访问不良的网站,会触发CSRF攻击,自动给黑客转账
- 原理是不良网站会嵌入一个post请求,包括了转账的url,转账人和金额的表单,而且把这个内容提交设为不可见,或者高度和宽度都为0,post请求还是访问网站就立马提交,非常高效和高隐蔽性
- 只要token不存储在cookies,把token放在头部,当CSRF触发时,提交的信息没有包括token,服务器就会拦截
- 当然也可以用refer来预防,因为CSRF请求的源地址不是银行的转账url,refer地址与CSRF地址不一致,服务器就拒绝此次请求
token是怎么解密的,解密方式是什么
- token包括header,保存加密方式等信息,用base64进行加密获取加密后的header值
- token包括payload,保存用户非私密信息,用base64加密获取加密后的
- token包括签名信息,利用自定义的secret秘钥,对加密后的header和payload的值进行字符串合并,然后用SHA256进行加密,获取签名信息,签名信息无法逆向解密,还可以防止header和payload被篡改
- token=加密后的header+加密后的payload+签名
- 当服务器把token给客户端,客户端发送token给服务器,服务器会对对header和payload进行解密,查看是否符合要求
- 然后对加密后的header和payload进行SHA256加密运算,如果获取的签名值和客户端发来的token签名值一致,表示认证通过
为什么charles装了证书,就可以抓包了,其中的原理是什么
- 证书的内容包括了公钥、过期时间、认证的机构名、指纹加密算法、证书的序列号、指纹,,指纹是证书其他内容用指纹算法进行hash加密获得的值,然后用CA机构的私钥去加密指纹,获得签名。证书就包含了之前的内容+签名了
- 客户端收到了数字证书后,会去浏览器查看有没有对应的CA,如果有就用CA的公钥对签名进行解密,获取指纹,对比证书里面的指纹,如果一致,表示证书是对的,就可以拿到服务器的公钥的
- 如果证书内容被篡改,或者的指纹也不一样,黑客由于没有CA的私钥,只能用自己的私钥对指纹进行加密获得签名。客户端获取黑客的证书,用CA的公钥解密获得指纹,这个指纹与证书的指纹进行对比,发现不一致,证书是假的。因为我们只信任CA的公钥,不信任黑客的公钥
- charles作为代理,当客户端访问百度的时候,charles作为服务器接收请求百度的内容,再讲这些内容作为请求发给百度服务器,百度服务器响应的内容先给到charles,charles再把响应信息给到浏览器,这时候出现了问题,浏览器并不知道charles是不是百度的服务器
- 所以在浏览器请求之前,浏览器先装上charles的证书,也就是信任charles作为CA机构,charles返回百度的响应,会伪造百度的数字证书。客户端拿到伪造的证书,会去CA查看,用charles的CA证书去验证伪造的百度证书,认证当然成功,因为浏览器信任了charles的根证书,所以charles伪造百度证书成功,浏览器就默认charles是百度的服务器。双方就进行请求和响应的操作了
selenium的原理是什么
- python和java的代码就是client端,driver就是一个服务器端,不同的浏览器有不同的driver,他们通过http传递selenium的代码,driver接收到代码就会转化成浏览器能识别的api接口,driver再充当客户端,把这些api接口的操作通过http发送给浏览器,浏览器就会执行api接口,并返回执行成功与否,服务器收到这些内容再把操作结果发给client端,client执行下一段代码,driver也相当于一个代理服务器
上传文件的用例怎么设计
- 功能测试
- 符合要求的文件上传成功
- 上传成功的文件名显示正常
- 可查看、下载上传成功的文件
- 删除上传成功的文件
- 替换上传成功的文件
- 上传文件是否支持中文
- 文件路径是否可手动输入
- 手动输入正确的文件路径上传成功
- 手动输入错误的文件路径上传失败
- 文件大小测试
- 文件大小为0kb的文件上传成功
- 文件大小等于限制大小上传成功
- 文件大小略小于限制大小上传成功
- 文件大小大于限制大小上传失败
- 上传的文件大小超过剩余的存储空间,上传失败
- 上传文件时空间已满,无法继续上传有内容的文件
- 文件名称测试:
- 文件名过长无法上传成功
- 文件名称达到最大限制上传成功
- 文件名包含特殊字符看需求
- 文件名全为中文,英文或者中英混合
- 文件格式测试
- 上传正确的格式
- 上传不允许的格式,无法上传
- 界面测试
- 上传成功提示语正确
- 上传失败提示语正确
- 说明性文字是否正确
- 界面美观性
- 性能测试
- 弱网下的测试
- 不同3G、4G网络测试
- 上传过程中断网,提示是否正常
- 安全测试:
- 上传exe文件
- 上传木马文件
- 没有授权的用户是否可以访问或者下载文件或者删除文件
- 文件误删除是否有数据备份,回收站恢复的功能
- 其他测试:
- 断网后,重新连接网络会不会上传
- 在后台运行会不会上传
- 来中断的时候会不会上传成功,比如电话、闹钟、短信
- 程序关闭后,文件是否会继续上传
- 在非wifi环境下,用流量下载是否有提示:在非wifi情况下,是否继续上传文件
装饰器你的了解有多少,装饰器加参数,或者函数加参数怎么设计
- 装饰品实际上是一个闭包函数,一般设计为了复用之前的功能,通过外层函数传参,内部函数参数为需要实现的其他函数名,最内层函数通过*args,*kwargs接受其他函数参数
- 源函数带参数和返回值的处理
import time
# 被装饰的函数带有返回值和参数的处理方式
def log(func):
# 内层函数需要传入参数,但不知道参数传入什么,所以使用万能的方式,*args,**kwargs
def improve_func(*args, **kwargs):
start_time = time.time()
# 可以确保源函数也有参数传入
# 函数有返回值,直接给一个返回值ret
ret = func(*args, **kwargs)
end_time = time.time()
print(f"运行的时间为:{end_time - start_time}")
# 最后返回ret即可
return ret
return improve_func
@log
def a(b=100):
for i in range(100000):
b += i
return b
def test_a():
print(a(20))
- 装饰器本身带参数的简单写法
import time
# 装饰器带参数的写法
# 在最外层加入参数
def log(info="默认参数"):
# 里面一层才是正常的装饰器的写法
def inter_log(func):
# 内层函数需要传入参数,但不知道参数传入什么,所以使用万能的方式,*args,**kwargs
def improve_func(*args, **kwargs):
start_time = time.time()
# 可以确保源函数也有参数传入
# 函数有返回值,直接给一个返回值ret
ret = func(*args, **kwargs)
end_time = time.time()
print(f"运行的时间为:{end_time - start_time}+{info}")
# 最后返回ret即可
return ret
# 先返回最内层的函数
return improve_func
# 再返回最外层的函数
return inter_log
@log(info="通通")
def a(b=100):
for i in range(100000):
b += i
return b
def test_a():
print(a(20))
三次握手和四次挥手你的理解
- 我说了三次握手是通过三次握手,刚刚好让客户端和服务器都具备接收和发送的功能,然后面试官就结束了,我说三次握手就这样结束了,后面他想问的点没get到
你是怎么做安全测试的
- 用的是ZAP的工具,这个工具比较傻瓜化,直接登录我们的网站,然后就和正常的网站进行操作,工具会自动帮我们录制脚本,自动跑安全
这个工具的原理是怎么样的,他们是怎么自动化做的安全测试
- sql注入:在输入框输入sql相关语句,获得
- 比如一个登录界面,输入账号密码,登录成功需要输入正确的账号和密码,select * from user where username=‘admin’ and password=‘xxxx’,只有两个条件都满足才能登录成功,在用户名输入admin’ or 1=1 – ,select * from user where username=‘admin’ or 1=1 – 'and password=‘xxxx’,后面的密码就会被注释,1=1永远为真,select执行成功,登录成功,或者获取所有的用户名信息的表格
- xss攻击:
- 反射型XSS,通过邮件或者其他方式,给用户链接,用户点击链接后,就会自动运行链接的js脚本,达到获取cookies或者其他攻击
- 存储型xss,用于论坛,博客,黑客把js代码直接留言到论坛或者博客,可以保存这些js代码到数据库,当其他用户访问论坛,浏览器就会自动读取当前页面的js代码,实现攻击
- CSRF攻击:
- CSRF的攻击是用户登录了一个银行网站,保存了cookies,当访问不良的网站,会触发CSRF攻击,自动给黑客转账
- 原理是不良网站会嵌入一个post请求,包括了转账的url,转账人和金额的表单,而且把这个内容提交设为不可见,或者高度和宽度都为0,post请求还是访问网站就立马提交,非常高效和高隐蔽性
- 只要token不存储在cookies,把token放在头部,当CSRF触发时,提交的信息没有包括token,服务器就会拦截
- 当然也可以用refer来预防,因为CSRF请求的源地址不是银行的转账url,refer地址与CSRF地址不一致,服务器就拒绝此次请求
你的po模式是怎么写的
Po模式大家都知道,你要把po模式的层次感描绘出来,为什么这么设计,需要听听课
你还有什么问题
- 问一下公司的薪资结构和绩效
- 问一下公司的涨薪+升职的途径
- 询问岗位信息,我们到岗了之后要从事什么样的工作
- 公司的测试技术栈是什么,公司用到的是什么架构的技术
- 服务器管理权限,本机家算计管理权限
- 针对员工有哪些培训和提升计划
- 团队正在经历的尚未解决的挑战是什么
- 团队内和团队之间如何沟通,比如测试团队和开发团队
总结一下你过去的工作,然后现在是想做软件测试,写几个能体现学到的东西的demo,主要是让面试官感受到你的真诚跟上进心