本文为博主原创,未经许可严禁转载。
本文链接:https://blog.csdn.net/zyooooxie/article/details/114380007
2年前分享过一期 软件测试的面试题 ;
今年有些想法,想换工作了,就重新整理了些,再做个分享。
个别答案 仁者见仁
个人博客:https://blog.csdn.net/zyooooxie
性能测试关注指标
答:
【被测系统的实际性能状况】TPS、事务平均响应时间、事务成功率、并发用户数
【整个系统环境的硬件资源使用情况】
1,服务器:服务器的CPU平均使用率小于70%,内存使用率小于75% [PerfMon Metrics Collector插件]
2,数据库:数据库连接数、数据库读写响应时长、数据库读写吞吐量
3,网络:网络吞吐量、网络带宽、网络缓冲池大小
4,缓存(Redis):静态资源缓存命中率、动态数据缓存命中率、缓存吞吐量
5,测试设备(压力发生器):CPU 利用率、处理器队列长度、内存利用率、内存交换页面数、磁盘 IO 状态、网卡带宽使用情况
APP性能测试关注点
答
内存
CPU占用率
流量
启动时长、启动速度
帧数(FPS)
电量
OSI七层网络结构图
答:
应用层
表示层
会话层
传输层
网络层
链路层
物理层
TCP/IP五层网络结构图
答:
物理层
链路层
网络层
传输层
应用层
也可以分为四层:
应用层
运输层
网络层
网络接口层
App测试的测试点
答:
1功能性测试
2兼容性测试:android版本、手机品牌、手机分辨率
3性能测试:耗电量、流量、cup、内存消耗、fps、响应时间、app启动时长、crash率
4网络测试:wifi\2G\3G\4G\5G、电信\移动\联通\无网 + 网络切换
5接口测试:关注数据的传送,数据的安全加密
6异常测试:交叉事件【来电、来短信、低电量等;待机,插拔数据线、耳机等操作】、异常性测试【断网、断电、服务器异常】
7交互测试:调用相机、分享功能
8安全测试:APP内涉及到用户的信息是否加密(数据在本地的存储、传输等、执行某些操作时导致的输入有效性验证、授权、数据加密等)
TCP、IP协议
TCP 的全称是Transmission Control Protocol ,传输控制协议。是一种面向连接的、可靠的、基于字节流的传输层通信协议。
它能够帮助你确定计算机连接到 Internet 以及它们之间的数据传输。通过三次握手来建立 TCP 连接。一旦连接建立后,就可以发送数据了,当数据传输完成后,会通过 四次挥手来断开连接。
IP的全称是Internet Protocol,网络之间互连的协议。
三次握手、四次挥手
答
三次握手,是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。在socket编程中,客户端执行connect()时,将触发三次握手。
- 首先客户端向服务端发送一个带有 SYN 标志,以及随机生成的序号(例如 1)的数据包;
- 服务端收到数据包后返回一个数据包(SYN为随机数(例如100),ACK为2)给客户端;
- 客户端再次发送带有 ACK 标志101序号的数据包给服务端;至此三次握手过程结束,客户端开始向服务端发送数据。
TCP的连接的拆除需要发送四个包,因此称为四次挥手。客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close()操作,即可产生挥手操作。
- 客户端发送带有 FIN 标识的报文给服务端,请求通信关闭;
- 服务端收到信息后,回复 ACK 答应关闭客户端通信(连接)请求;
- 服务端发送带有 FIN 标识的报文给客户端,也请求关闭通信;
- 客户端回应 ACK 给服务端,答应关闭服务端的通信(连接)请求;
PO模式
page object model 简称:POM/PO,PO模式最核心的思想是分层,把页面元素定位和业务操作流程分开,实现脚本重复使用及脚本易维护性。【UI元素的改变不需要修改业务逻辑代码。只需要找到对应的PO页修改定位即可,数据代码分离】
PO模式主要分三层:
1.基础层BasePage:封装一些最基础的selenium的原生的api方法,元素定位,框架跳转等。
2.PO层:元素定位、获得元素对象,页面动作
3.测试用例层:业务逻辑,数据驱动。
三者的关系:PO层继承基础层,测试用例层调用PO层。
搭建的自动化测试框架 结构是怎么样的
略
系统架构、中间件
略
接口测试咋测
答:
通过性验证:正常场景【首先肯定要保证这个接口功能是好使的,按照接口文档上的参数,正常传入,是否可以返回正确的结果】、异常场景。
边界测试:不按照你接口文档上的要求输入参数,测试其边界情况【必选和非必选、长度、字符类型、为空、缺失、组合、重复】
参数组合:不同参数的组合。
异常情况测试:重复提交、并发测试【一个账号,同时(大于2个请求)对最后一个商品下单,或不同账号,对最后一个商品下单】、大数量提交
性能测试:接口响应时间、并发数、吞吐量、服务器资源利用率
安全测试:敏感信息加密【userName\pwd】、绕过身份授权【群主、群员、非群友】
日志报错:Java的Exception
答:
1 ArrayIndexOutOfBoundsException 数组越界异常【用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引】
2 NullPointerException 空指针异常【当应用程序试图在需要对象的地方使用 null 时,抛出该异常】
3 IllegalArgumentException 非法参数异常【抛出的异常表明向方法传递了一个不合法或不正确的参数】
4 NegativeArraySizeException 数组长度为负异常【如果应用程序试图创建大小为负的数组,则抛出该异常】
5 IllegalStateException 非法状态异常【在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下】
6 ClassCastException 类型转换异常【当试图将对象强制转换为不是实例的子类时,抛出该异常】
UnsupportedOperationException - 不支持的操作异常
SecurityException - 安全异常
NumberFormatException - 数字格式异常
ArrayStoreException - 向数组中存放与声明类型不兼容对象异常
ArithmeticException - 算术运算异常
IndexOutOfBoundsException - 下标越界异常
python面试题
is 和==的区别
答
is 判断的是 a 对象是否就是 b 对象,是通过 id 来判断的。
== 判断的是 a 对象的值是否和 b 对象的值相等,是通过 value 来判断的。
求字符串逆序(翻转)
答
gl_abc = 'zyooooxie+csdn-XIE'
def str_nixu_1():
# 字符串 步长-1
print(gl_abc[::-1])
def str_nixu_2():
abc_list = list(gl_abc)
# 列表 切片反转
abc_list = abc_list[::-1]
print(''.join(abc_list))
def str_nixu_3():
# 列表的reverse()
abc_list = list(gl_abc)
abc_list.reverse()
print(''.join(abc_list))
def str_nixu_4():
# reversed
abc = reversed(gl_abc)
print(''.join(list(abc)))
求某个数的正约数
答
【正约数:可以整除 + 包括1和本身】
举例:
10的正约数有:1、2、5、10。
12的正约数有:1、2、3、4、6、12。
def yueshu_fun_1(test_num: int):
all_data = list()
for i in range(test_num):
if i == 0:
continue
if test_num % i == 0:
all_data.append(i)
all_data.append(test_num) # 一个数的约数必然包括1及其本身
print(all_data)
def yueshu_fun_2(test_num: int):
all_data = list()
for i in range(test_num // 2):
print(i)
if i == 0:
continue
abc = test_num % i
if abc == 0:
all_data.append(i)
all_data.append(int(test_num / i))
print(set(all_data))
写个list的冒泡排序
答
【冒泡排序:比较相邻的元素,如果前一个比后一个大,交换之。】
list_test = [1, 3, 110, 9, 21, 35, 34, 6]
change_times = len(list_test) - 1
for i in range(change_times):
i += 1
print("第%s轮 交换前数据list:%s" % (i, list_test))
for e in range(i)[::-1]:
print(e)
if list_test[e + 1] < list_test[e]:
list_test[e], list_test[e + 1] = list_test[e + 1], list_test[e]
print("第 %s 轮交换后数据list:%s" % (i, list_test))
鸡兔同笼
答
2种思路:
from sympy import *
def sympy_fun(all_num, all_foot):
# SymPy库
x = Symbol('x')
y = Symbol('y')
print(solve([(x * 2 + y * 4) - all_foot, x + y - all_num], [x, y]))
def test_fun(all_num, all_foot):
# for循环
abc_list = list()
ABC_list = list()
for abc in range(all_num):
ABC = all_num - abc
# print(abc * 2 + ABC * 4, all_foot)
if abc * 2 + ABC * 4 == all_foot:
abc_list.append(abc)
ABC_list.append(ABC)
print(abc_list)
print(ABC_list)
test_fun(160, 368)
sympy_fun(160, 368)
二分法
需求:使用二分法 求某元素不重复、升序的list【长度小于1000】 的 某元素的索引;若元素不存在 返回 -1
递归限制 一个小实例
【我觉得 面试官的这个需求有问题:使用 二分法 多此一举(因为元素不重复,索引直接index();元素重复,使用enumerate+列表推导式)】
gl_list = [1, 1, 17, 100, 100, 100, 100, 100, 100, 100, 23231, 2323123231]
def find_fun(test_list: list, test_ele):
all_list = [ele_index for ele_index, ele in enumerate(test_list) if ele == test_ele]
print(all_list)
find_fun(gl_list, 100)
gl_list_no = [1, 8, 17, 45, 51, 55, 96, 100, 1012, 5656, 23231, 2323123231]
def find_fun_no(test_list: list, test_ele):
if test_ele in test_list:
index = test_list.index(test_ele)
print(index)
else:
print(list())
find_fun_no(gl_list_no, 100)
二分法 查找某元素
# 假设list的元素是按升序排列,将中间位置ele 与查找ele比较,如果两者相等,则查找成功;
# 否则利用中间位置ele 将list分成前、后两个子list,如果中间位置ele 大于查找ele,则进一步查找前一子list,否则进一步查找后一子list。
# 重复以上过程,直到找到满足条件的ele;或直到子list 所有ele不符合为止。
gl_list = [1, 8, 17, 45, 51, 55, 96, 100, 1012, 5656, 23231, 2323123231]
# 查找100在gl_list【若不在list,返回-1】
def find_fun(test_list: list, test_ele):
print('list:{}'.format(test_list))
# 返回-1
if test_list.count(test_ele) == 0:
return -1
# 递归
len_list = len(test_list)
a = test_list[int(len_list / 2)]
print('中位元素{}'.format(a))
if test_ele > a:
find_fun(test_list[int(len_list / 2):], test_ele)
elif test_ele < a:
find_fun(test_list[:int(len_list / 2)], test_ele)
else:
print('找到元素')
find_fun(gl_list, 100)
非得实现需求
因为元素不重复,索引直接index(); 【计算ele 在子list的index, 我没能成功实现需求】
import copy
gl_list = [1, 8, 17, 45, 51, 55, 96, 100, 1012, 5656, 23231, 2323123231]
# 非要 查找100 在gl_list的index
# 【若不在list,返回-1】
def find_fun(test_list: list, test_ele, deep_list=None):
print('list:{}'.format(test_list))
if deep_list is None:
deep_list = copy.deepcopy(test_list)
# # 跳出
# if len(test_list) == 1 and test_list.count(test_ele) == 0:
# return
# 返回-1
if test_list.count(test_ele) == 0:
return -1
# 递归
len_list = len(test_list)
a = test_list[int(len_list / 2)]
print('中位元素{}'.format(a))
if test_ele > a:
index = find_fun(test_list[int(len_list / 2):], test_ele, deep_list=deep_list)
return index
elif test_ele < a:
index = find_fun(test_list[:int(len_list / 2)], test_ele, deep_list=deep_list)
return index
else:
print('找到元素')
res_index = deep_list.index(test_ele)
print('index【因为元素不重复】:{}'.format(res_index))
return res_index
a = find_fun(gl_list, 96)
print(a)
列表和元组的相同、不同?
答
相同点:
都是序列;都可以存储任何数据类型;可以通过索引访问;
不同点:
使用方括号[]创建列表,而使用括号()创建元组;元素是否可变;是否重用与拷贝;
json和dict有什么区别?
答
1,json指的是类似于javascript对象的一种数据格式对象;dict是python的数据结构;
2,json的类型是字符串,字典的类型是字典。
3,json的key只能是字符串,python的dict可以是任何可hash对象(hashtable type)
4,json的key可以是有序、重复的;dict的key不可以重复。
5,json的字符串强制双引号,dict字符串可以单引号、双引号;
6,json定义布尔值和空值:true、false、null。python定义布尔值和空值:True、False、None。
7,json中文必须是unicode编码
列表和字典有什么区别?
答
(1)获取元素的方式不同。列表通过索引值获取,字典通过键获取。
(2)数据结构和算法不同。字典是hash算法,搜索的速度特别快。
(3)占用的内存不同。
pytest
答
Pytest的插件:
接触到的有pytest-HTML(HTML测试报告),pytest-rerunfailures(失败情况下重复执行)、pytest-allure(allure测试报告)、pytest-ordering (自定义用例的执行顺序)、pytest-xdist(分布式测试)
Pytest对参数化的处理:
pytest.mark.parametrize装饰器、pytest.fixture()
Pytest的使用规范:【可自定义】
测试文件名必须以“test_”开头
测试类以Test开头,并且不能带有 init 方法
测试方法必须以“test_”开头
除了有setup/teardown,还能更自由的定义fixture装载测试用例
Pytest的mark:
1,无条件跳过测试pytest.mark.skip
2,有条件跳过测试pytest.mark.skipif
3,标记测试功能按预期失败pytest.mark.xfail
4,将测试功能标记为使用给定的夹具名称pytest.mark.usefixtures
5,向特定测试项添加警告过滤器,以便更好地控制应在测试,类甚至模块级别捕获哪些警告@pytest.mark.filterwarnings
6,自定义标记:标记指定标签
allure的测试报告:
1,@allure.severity(优先级/严重等级)
包含blocker, critical, normal, minor, trivial
2,标记功能分组:
epic、feature、story、tag,包含关系的话是 从左到右,越来越小
Title、description
3,@allure.step(描述) 用装饰器
4,动态生成allure.dynamic
写的测试用例 包括哪些内容
答
用例目录 用例名称 需求ID 前置条件 用例步骤 预期结果 用例类型 用例状态 用例等级 创建人 执行结果 备注
SDK 咋测
答
测得内容:
1,SDK接口和文档
SDK接口是测试的主要对象,也是核心的内容。
2,SDK日志
当上层调用时遇到问题,只能依赖SDK打印的日志来定位分析。所以SDK日志是否完备,是否有助于解决问题。
3,Demo或行业解决方案
Demo是SDK提供方用来示例如何调用接口实现具体的功能,也可以作为开发者直观感受SDK接入效果
git常用命令
答
撤销提交 git reset
初始化 git init
克隆 git clone
git配置 git config [--global] user.name "[name]" git config [--global] user.email "[email address]"
Git 添加暂存区 git add
Git 提交到仓库 git commit
Git分支 git branch
切换分支 git checkout
合并 git merge
推送 git push
拉取 git pull
显示有变更的文件 git status
显示当前分支的版本历史 git log
正则
答
-
括号
[] 方括号:内包括需要匹配的字符
{} 花括号:指定匹配字符的数量
() 圆括号:用来分组 -
开始结束符号
^:表示开始
$:表示结束 -
一些快捷命令
.:代替任意1个字符(除了\n)
\d:代替[0-9],表示匹配0至9的数字
\w:代替[a-z][0-9][_]
\s:代表任意空白符
*:0次或多次发生
+:至少一次发生
?:0或1次发生
adb命令
答
adb 使用的端口号是5037
1查看帮助手册列出所有的选项说明及子命令:adb help
2获取设备列表及设备状态:adb devices
3安装应用:adb install 路径\xx.apk; adb install -r 重新安装。
Shell安装应用:adb shell pm install 路径\xx.apk,
4获取设备的状态:adb get-state
设备的状态有 device , offline , unknown3种,其中device:设备正常连接,offline:连接出现异常,设备无响应,unknown:没有连接设备。
5卸载应用:adb uninstall <包名>
Shell卸载应用:adb shell pm uninstall <包名>
6将 Android 设备上的文件复制到电脑本地:adb pull <远程路径> <本地路径>
7推送本地文件至 Android 设备:adb push <本地路径> <远程路径>
8结束和启动adb服务:adb kill-server /adb start-server
9打印 Android 的系统日志:adb logcat
10清除系统日志:adb logcat -c
11重启 Android 设备:adb reboot
12返回设备序列号SN值:adb get-serialno
13获取设备的ID:adb get-product
14进入设备shell:adb shell
15列出所有的应用的包名:adb shell pm list package
-s: 只显示系统包名; -3: 只显示第3方应用的包名;
16截屏并保存至 sdcard 目录: adb shell screencap -p /sdcard/1.png
17录制视频并保存至sdcard:adb shell screenrecord /sdcard/record.mp4,执行命令后操作手机,ctrl + c 结束录制
18列出应用的 dump 信息,adb shell pm dump 包名
19查看当前终端中的进程信息:adb shell ps
20启动某app:adb shell am start -n 包名/activity
21某 APP 关闭:adb shell am force-stop 包名
平时使用到的curl
答
1在不加任何选项使用curl时,来获取链接内容到标准输出; curl https://blog.csdn.net/zyooooxie
2自动跳转: 使用 -L 参数,curl就会跳转到新的网址; curl -L https://blog.csdn.net/zyooooxie
3显示头信息: -i 参数可以显示http response的头信息,连同网页代码一起。curl -i https://blog.csdn.net/zyooooxie
4-X 用于指定发送数据的方式:
GET方法 curl https://blog.csdn.net/zyooooxie?data=xxx
POST方法必须把数据和网址分开,curl就要用到–data/-d ;curl -X POST -d “data=xxx” https://blog.csdn.net/zyooooxie
Delete方法 curl -X DELETE https://blog.csdn.net/zyooooxie
5cookie: 使用–cookie参数,可以让curl发送cookie。 curl --cookie “name=xxx” https://blog.csdn.net/zyooooxie
6使用 -A 自定义 User-Agent :curl -A “Mozilla/5.0 Gecko/35.0 Firefox/35.0” https://blog.csdn.net/zyooooxie
7使用 -H 自定义 header:curl -H “Referer: blog.csdn.net” -H “User-Agent: Custom-zyooooxie-Agent” http:/blog.csdn.net/zyooooxie
sql的通配符
答
% 替代 0 个或多个字符
_ 替代一个字符
[charlist] 字符列中的任何单一字符
[!charlist] 不在字符列中的任何单一字符
SELECT * FROM Persons WHERE City LIKE ‘Ne%’;
MySQL 中使用 REGEXP 或 NOT REGEXP 运算符 (或 RLIKE 和 NOT RLIKE) 来操作正则表达式:
where name rlike ‘[张李]’
where name REGEXP ‘^[张李]’
面试题目暂时先分享这些;
下一篇面试分享 可能又得等几年了。
【不换工作,我是想不到去整理这些的 = = 】
可能还会更新一篇 面试心态的分享 ,有兴趣 可以看看。
交流技术 欢迎+QQ 153132336 zy
个人博客 https://blog.csdn.net/zyooooxie