软件测试面试问题【2】

本文为博主原创,未经许可严禁转载。
本文链接: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()时,将触发三次握手。

  1. 首先客户端向服务端发送一个带有 SYN 标志,以及随机生成的序号(例如 1)的数据包;
  2. 服务端收到数据包后返回一个数据包(SYN为随机数(例如100),ACK为2)给客户端;
  3. 客户端再次发送带有 ACK 标志101序号的数据包给服务端;至此三次握手过程结束,客户端开始向服务端发送数据。

TCP的连接的拆除需要发送四个包,因此称为四次挥手。客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close()操作,即可产生挥手操作。

  1. 客户端发送带有 FIN 标识的报文给服务端,请求通信关闭;
  2. 服务端收到信息后,回复 ACK 答应关闭客户端通信(连接)请求;
  3. 服务端发送带有 FIN 标识的报文给客户端,也请求关闭通信;
  4. 客户端回应 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. 括号
    [] 方括号:内包括需要匹配的字符
    {} 花括号:指定匹配字符的数量
    () 圆括号:用来分组

  2. 开始结束符号
    ^:表示开始
    $:表示结束

  3. 一些快捷命令
    .:代替任意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

Guess you like

Origin blog.csdn.net/zyooooxie/article/details/114380007