接口自动化大杂烩总结--日常+面试必备

一、接口基础

1、接口:前后端沟通的桥梁,数据传输通道,包括:外部接口,内部接口

2、接口类型:HTTP接口、web Service接口、Restful接口

3、HTTP:超文本传输协议,用户传输html超媒体文档的应用层协议,是在web上进行数据交换的基础,是一种client-server协议

  • http支持客户端/服务器模式,客户端发送请求,服务器响应数据,常用的方法:get、post、put、delete
  • http协议简单灵活,服务器的程序规模小,通信速度快,对事物处理没有记忆能力,一次请求响应完毕后,就会断开连接,也不保存连接状态,下一次客户端向同样的服务器发起请求时,由于他们已经忘了彼此,需要重新进行连接,限制每次连接只处理一个请求,完成请求和应答后就断开连接,节约传输时间

4、http与https:

  • https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
  • http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
  • http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  • (这个只是默认端口不一样,实际上端口是可以改的)
  • http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

5、cookie和session

  • cookie存储在客户端,大数据存储在浏览器,session用于控制客户端和服务器的连接,session存储在服务器
  • 存储容量不同,cookie有上线,session无上限
  • 存储方式不同,cookie有限制,session可以存储任何类型的数据
  • 安全性不同,cookie不安全,可以篡改
  • 有效期:cookie可以设置长期有校,session如果设置超时时间过长,容易导致内存溢出
  • 服务器压力不同,session存储在服务器端,当访问增多,会比较占用服务器的性能

6、cookie应用场景:用户的登录状态,记录用户的习惯,购物车

7、session应用场景:登录验证

8、get、post请求区别:

以get请求为例分析下请求过程

1).浏览器请求tcp连接(第一次握手);

2).服务器答应进行tcp连接(第二次握手);

3).浏览器确认,并发送get请求头和数据(第三次握手,这个报文比较小,所以http          会在此时进行第一次数据发送);

4).服务器返回200OK响应;

  • get参数通过url传递,post放在request body中
  • get请求再url中传递的参数是有长度限制的,post没有
  • get比post更不安全,因为参数直接暴露在url中,所以不能传输敏感信息
  • get请求只能进行url编码,而post支持多种编码方式
  • get请求参数会被完整的保留在浏览历史记录里,而post中的参数不会被保留
  • 对于get请求,浏览器会把 请求头和data一并发出去,服务器响应返回数据
  • 对于post请求,浏览器先发送header、服务器响应100,然后继续,浏览器再发送data,服务器响应200,返回数据

9、http请求报文/响应报文的组成:

request:请求行、请求头部、请求数据

response:状态行、消息报文、响应正文

10、常见响应状态码

  • 1XX 信息性状态码
  • 2XX成功状态码
  • 3XX重定向状态码
  • 4XX客户端错误状态码
  • 5XX服务器错误状态码

11、常见响应头含义

  •       Allow:服务器支持哪些请求方法(如GET、POST等)。
  • Content-Encoding:告诉浏览器,服务器的数据压缩(Encode)格式。实体报头域被使用作媒体类型的修饰符,它的值指示了已经被应用到实体正文的附加内容编码,因而要获得Content- Type报头域中所引用的媒体类型,必须采用相应的解码机制。有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。
  • Content- Type:告诉浏览器,回送数据的类型。Servlet默认为text/plain,但通常需要显式地指定为text/html。
  • Date:当前的GMT时间,例如,Date:Mon,31Dec200104:25:57GMT。Date描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。可以用setDateHeader来设置这个头以避免转换时间格式的麻烦。
  • Expires:告诉浏览器把回送的资源缓存多长时间,-1或0则是不缓存。
  • Last-Modified:告诉浏览器当前资源缓存最后改动时间。客户可以通过If-Modified-Since请求头提供一个日期,该请求将被视为一个条件GET,只有改动时间迟于指定时间的文档才会返回,否则返回一个304(Not Modified)状态。Last-Modified也可用setDateHeader方法来设置。
  • Location:响应报头域用于重定向接受者到一个新的位置,这个头配合302状态码使用,告诉客户端找谁,用于重定向接收者到一个新URI地址。表示客户应当到哪里去提取文档。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302。
  • Refresh:告诉浏览器隔多久刷新一次,以秒计。
  • Server:服务器通过这个头告诉浏览器服务器的类型。Server响应头包含处理请求的原始服务器的软件信息。此域能包含多个产品标识和注释,产品标识一般按照重要性排序。Servlet一般不设置这个值,而是由Web服务器自己设置。
  • Set-Cookie:设置和页面关联的Cookie。Servlet不应使用response.setHeader(“Set-Cookie”, …),而是应使用HttpServletResponse提供的专用方法addCookie。
  • Transfer-Encoding:告诉浏览器,传送数据的编码格式。
  • WWW-Authenticate:客户应该在Authorization头中提供什么类型的授权信息?在包含401(Unauthorized)状态行的应答中这个头是必需的。
  • setContentType:设置Content-Type头。大多数Servlet都要用到这个方法。
  • setContentLength:设置Content-Length头。对于支持持久HTTP连接的浏览器来说,这个函数是很有用的。
  • addCookie:设置一个Cookie(Servlet API中没有setCookie方法,因为应答往往包含多个Set-Cookie头)。
  • Cache-Control:控制浏览器不要缓存数据   no-cache

12、浏览器地址输入url,回车访问会经历怎样的过程?

  • 浏览器向DNS服务器请求解析该URL中的域名所对应的IP地址
  • 解析出IP地址后,根据该IP地址和默认端口号80,和服务器建立TCP连接
  • 浏览器发出读取文件的HTTP请求,该请求报文作为TCP三次握手的第三个报文的数据发给服务器
  • 服务器对浏览器请求做出响应,并把对应的html文本发送给浏览器
  • 释放tcp连接
  • 浏览器将该html文本显示内容

13、接口依赖token的处理思路:

  • 抽取登录接口返回值中的token---->jsonpath
  • 使用全局变量存储token
  • 其它接口将token放入请求头,发送请求

14、接口测试的流程

  • 需求评审,熟悉业务和需求
  • 开发提供接口文档
  • 根据开发交付的接口文档,编写接口测试用例
  • 接口用例评审
  • 执行接口测试
  • 提交接口测试报告

15、常见接口文档的基本组成

  • 接口说明
  • 调用url
  • 请求方法(get、post)
  • 请求参数、参数类型、请求参数说明等
  • 返回参数说明

16、如何设计接口测试用例

以功能测试角度为例:业务功能:正常场景、异常场景;边界值:必填、组合可选参数、参数有无、null、参数的顺序、个数、类型、参数字符串长短、参数包含特殊字符

其它类型测试:性能测试、安全测试(前后端数据传输是否加密传输)

二、requests模块-get、post请求

1、get请求

语法格式:requests.get(url, params=None, **kwargs)

如:requests.get(url=url, headers=headers, params=params)

  • url:请求url地址
  • headers:请求头
  • params:参数
import requests
url = 'https://api.apiopen.top/getJoke'
data = {
    "page": 10,
    "count": 5,
    "type": "video"
}
res = requests.get(url=url, data=data)
# 获取响应状态码
print(res.status_code)
# 获取响应消息
print(res.content)
# 获取响应数据,文本格式
print(res.text)
# 获取cookie
print(res.cookies)
print(res.json())

2、post请求

1)分析源码

 

2)什么时候传入data、什么时候传入json?

post请求参数到底是传data还是json,这时候我们要看请求头里的content-type类型

  • 不管json是str还是dict,如果不指定headers中的content-type,默认为application/json;
  • data为dict时,如果不指定content-type,默认为application/x-www-form-urlencoded,相当于普通form表单提交的形式;
  • data为str时,如果不指定content-type,默认为application/json。

3)基本使用方法

res=requests.post(url=url,data=data)
res=requests.post(url=url,json=data,headers=headers)
# 获取响应状态码
print(res.status_code)
# 获取响应消息
print(res.content)
# 获取响应数据,文本格式
print(res.text)
# 获取cookie
print(res.cookies)
print(res.json())

三、cookie、session、token的应用

1、cookie应用

1)、发送登录接口请求,获取cookie

cookies=res.cookies

2)、另一个接口发送请求时携带登录cookie

接口2=requests.post(url=url,json=data,cookies=cookies)

2、session应用

1)创建session会话管理

session=requests.session()

2) 登录接口=session.post(url=url,data=data)

3) 依赖session接口2=session.post(url=url,data=data)

3、token应用

场景:接口2依赖登录接口的返回值token,才能正常请求

1)发送登录接口请求获取token值

token=login_response.json()["token"]

2)第二个接口

headers={“authorization”:token}

接口2请求=requests.get(url=url,headers=headers)

4、小结:如何选token、session、cookie

token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登陆后,服务器生成一个token并将此token返回给客户端,以后客户端只需带上这个token请求数据即可,无需带上用户名和密码,所以对于中小型网站 cookie、session足矣,如果是企业级网站,并需要处理大量请求,token更适合

四、requests请求封装

分析get、post、request源码,总结:不管是get、post还是其它请求类型,最终都是回调request函数

import requests
class RequestHandler:
    def __init__(self):
        """ session管理器"""
        self.session=requests.session()
    def visit(self,method,url,params=None,data=None,json=None,headers=None,**kwargs):
        return self.session.request(method,url,params=params,data=data,json=json,headers=headers)
    def close_session(self):
        """ 关闭session"""
        self.session.close()

五、Unittest框架

1、单元测试:对于接口测试来讲,单元测试就是将访问接口的过程封装在函数里面,接口测试就变成了单元测试,单元测试是对某个模块,某个类,某个函数进行结果输出后的验证测试,而对于测试来讲,单元测试就是为了执行测试用例,常用框架:unittest、pytest,unittest常用作接口自动化,后者常用作web、app自动化。

2、unittest组成:TestCase(测试用例),TestSuite(测试套件),TestRunner(测试运行器),TestFixture(测试环境数据准备和清理) 。

3、unittest实现思路:

  • 导入unittest
  • 创建一个测试类,继承unittest.TestCase方法
  • 重写setUp和tearDown(非必要)
  • 定义以test开头的测试函数,识别测试用例
  • 调用unittest.main()方法运行测试用例
  • 用例执行后设计,断言比对测试是否通过
  • 查看测试结果

4、setUp函数:初始化环境;

tearDown函数:清洗环境

执行顺序是:setUp->testA->tearDown->setUp->testB>tearDown

5、收集测试用例,使用TestSuite()

suite=unittest.TestSuite()

suite.addTest("用例名称")

6、使用TestLoader加载测试用例

1)使用测试类加载用例(loadTestsFromTestCase)

suite=unittest.TestSuit()

    loader=unittest.TestLoader()

    suite.addTest(loader.loadTestsFromTestCase(测试用例类名1))

2)使用测试类所在模块加载用例

suite=unittest.TestSuit()

loader=unittest.TestLoader()

suite.addTest(loader.loadTestsFromTestCase(测试用例模块名))   #测试用例模块名直接传入

7、生成测试报告:HTMLTestRunner、nnreport->BeautifulReport

report = nnreport.BeautifulReport(f)
report.report(file_title, filename, log_path=".")

8、常用断言方法

序号

断言方法

断言描述

1

assertEqual(arg1, arg2, msg=None)

验证arg1=arg2,不等则fail

2

assertNotEqual(arg1, arg2, msg=None)

验证arg1 != arg2, 相等则fail

3

assertTrue(expr, msg=None)

验证expr是true,如果为false,则fail

4

assertFalse(expr,msg=None)

验证expr是false,如果为true,则fail

5

assertIs(arg1, arg2, msg=None)

验证arg1、arg2是同一个对象,不是则fail

6

assertIsNot(arg1, arg2, msg=None)

验证arg1、arg2不是同一个对象,是则fail

7

assertIsNone(expr, msg=None)

验证expr是None,不是则fail

8

assertIsNotNone(expr, msg=None)

验证expr不是None,是则fail

9

assertIn(arg1, arg2, msg=None)

验证arg1是arg2的子串,不是则fail

10

assertNotIn(arg1, arg2, msg=None)

验证arg1不是arg2的子串,是则fail

11

assertIsInstance(obj, cls, msg=None)

验证obj是cls的实例,不是则fail

12

assertNotIsInstance(obj, cls, msg=None)

验证obj不是cls的实例,是则fail

六、excel数据分离及ddt实现数据驱动

1、openpyxl:一个excel对应一个workbook对象,一个sheet对应一个worksheet对象,而一个单元格对应一个cell对象

2、基本操作

 # 读取excel文件

    workbook = openpyxl.load_workbook(path)

    # 读取所有sheet

    sheet = workbook.get_sheet_names()

    # 获取某个sheet

    sheet = workbook[sheet[0]]

    # 获取某个cell的值

    cell_val = sheet.cell(row=2, column=2).value

3、封装读取excel方法

from openpyxl import load_workbook
class DoExcel:
    def __init__(self,filepath):
        self.wb = load_workbook(filepath)
        self.sh = self.wb["Sheet1"]
    def read_all_casedatas(self):
        all_casedatas = []
        for row in range(2,self.sh.max_row+1):
            case_data ={}
            case_data["case_id"] = self.sh.cell(row =row,column =2).value
            case_data["url"] = self.sh.cell(row =row,column =3).value
            case_data["method"] = self.sh.cell(row =row,column = 4).value
            case_data["request_data"] = self.sh.cell(row =row,column =5).value
            case_data["expect_data"] = self.sh.cell(row =row,column =6).value
            case_data["compare_type"] = self.sh.cell(row =row,column =7).value
            all_casedatas.append(case_data)
        return all_casedatas

4、ddt简介

  • 名称:数据驱动测试
  • 作用:由外部数据集合来驱动测试用例的执行
  • 核心思想:数据和代码分离
  • 应用场景:一组数据来执行相同的操作
  • 优点:当测试数据发生大量变化的情况下,测试代码可以保持不变
  • 实际应用:excel存储测试数据,ddt读取测试数据到单元测试框架,参数化的应用

5、ddt中的:ddt、data、unpack

  • ddt:装饰类
  • data:装饰测试方法,参数是一系列的值
  • unpack:传递的是复杂的数据结构时使用,比如元组或列表,添加unpack之后,ddt会自动把元组或者列表对应到多个参数上,字典也可以这样处理;当没有加unpack时,方法的参数只能填一个。

6、具体使用举例:

七、接口自动化-配置文件

1、配置文件的几种形式:yaml、py文件、ini文件

2、实例:py形式的配置文件

import os
# abspath获取当前文件所在的绝对路径
BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 存放测试用例
CASE_PATH = os.path.join(BASE_PATH, "testcases")
# 存放测试报告
REPORT_PATH = os.path.join(BASE_PATH, "report")
# 存放日志文件
LOG_PATH = os.path.join(BASE_PATH, "logs")
# 存放测试数据
DATA_PATH = os.path.join(BASE_PATH, "testdatas")
# mysql连接信息
MYSQL_INFO = {
    "host": "",
    "user": "",
    "password": "",
    "port": 3306,
    "db": "",
    "charset": 'utf8',
    "autocommit": True,
}
# redis连接信息
REDIS_INFO = {
    "host": "",
    "password": "",
    "port": 6379,
    "db": 0,
}

八、pymysql、及redis数据库操作

import pymysql
from AutoApiTest.config import config
import redis


class MysqlUtil:
    def __init__(self):
        self.__connection = pymysql.connect(**config.MYSQL_INFO)
        self.cursor = self.get_mysql_cursor()
        # self.cursor = self.__connection.cursor()
    def get_mysql_cursor(self):
        return self.__connection.cursor()
    def execute(self, sql):
        config.log.info("执行的sql是%s" % sql)
        return self.cursor.execute(sql)
    def fetchall(self):
        return self.cursor.fetchall()
    def fetchone(self):
        return self.cursor.fetchone()
    def fetchmany(self):
        return self.cursor.fetchmany()
    def __del__(self):
        self.cursor.close()
        self.__connection.close()


class RedisUtil:
    def __init__(self):
        self.redis = redis.Redis(**config.REDIS_INFO)
        ""
    def get(self, key):
        return self.redis.get(key)
    def set(self, key, value):
        return self.redis.set(key, value)
    def hget(self, key, field):
        return self.redis.hget(key, field)
    def hset(self, key, field, value):
        return self.redis.hset(key, field, value)

九、日志模块的应用

1、常见日志的级别:

  • DEBUG:调试级别(Value=10),打印非常详细的日志信息,通常仅在Debug时使用,如算法中每个循环的中间状态;
  • INFO:信息级别(Value=20),打印一般的日志信息,突出强调程序的运行过程 ,主要用于处理请求或者状态变化等日常事务;
  • WARNING:警告级别(Value=30),打印警告日志信息,表明会出现潜在错误的情形,如某些预期之外的情况发生或者在将来可能发生什么,此情况一般不会影响软件的正常实用,如用户登录密码错误;
  •  ERROR:错误级别(Value=40),打印错误异常信息,该级别的错误可能会导致系统的一些功能无法正常使用,如IO操作失败或者连接问题;
  • CRITICAL:严重错误(Value=50),一个严重的错误,导致系统可能无法继续运行,如内存耗尽、磁盘空间为空,一般很少使用;

2、logging模块基本构成

  • Logger:日志
  • LogRecord:日志记录器,将日志传到相应的处理器处理
  • Handler:处理器,将日志记录发送到合适的目的地
  • Filter:过滤器,提供更好的粒度控制,可以决定输出哪写日志记录
  • Formatter:格式化,指定日志格式输出的布局

3、基本实现步骤:

# 创建一个logger
logger = logging.getLogger('mylogger')
logger.setLevel(logging.DEBUG)
# 创建一个handler,用于写入日志文件
cunTime = time.strftime("%Y-%m-%d %H%M",time.localtime())
fh = RotatingFileHandler(conf_dir.logs_dir+"/Api_Autotest_log_{0}.log".format(cunTime),backupCount=20,encoding='utf-8')
fh.setLevel(logging.DEBUG)
# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# 定义handler的输出格式
formatter = logging.Formatter('[%(asctime)s][%(thread)d][%(filename)s][line: %(lineno)d][%(levelname)s] ## %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# 给logger添加handler
logger.addHandler(fh)
logger.addHandler(ch)

十、接口自动化--动态数据处理

场景:接口测试用例中需要生成不同的手机号

解决办法:

  • 在测试用例中将手机号字段写死{"mobile":“#phone#”,"pwd":123}
  • 定义一个动态生成手机号的方法
  • 从excel中读取测试用例
  • 判断测试用例中是否包含#phone#
  • 如果包含,则调用随机生成手机号的方法
  • 如果这个手机号存在于数据库中,重新生成
  • 如果不存在于库中,则用str.replace(old,new)动态替换数据

十一、接口自动化框架搭建思路

1、基本设计思路:数据驱动+结构分层

数据驱动:将维护数据与代码分离,接口调用行为一致,针对不同的参数组合驱动 不同的测试场景,减少代码冗余

结构分层:数据层+用例层+逻辑层

数据层:测试数据支撑的.xls文件

用例层:用例执行的test_myrequest文件

逻辑层:封装的do_db,do_excel等方法

 

十二、常见面试题总结

1、平时常见的接口测试产生的bug:常规错误,接口未实现,未按照约定返回结果,边界值处理错误,输入异常值,接口报错,接口明文传输,性能问题等等

2、接口测试如何开展的-->见上文接口测试流程

3、接口测试怎么测->见上文接口测试用例设计方法

4、session和cookie的区别

5、get和post区别

6、测试数据的存放位置

  • 对于账号密码,这种管全局的参数,可以用命令行参数,单独抽出来,写的配置文件里(如ini);
  • 对于一些一次性消耗的数据,比如注册,每次注册不一样的数,可以用随机函数生成;
  • 对于一个接口有多组测试的参数,可以参数化,数据放yaml,text,json,excel都可以;
  • 对于可以反复使用的数据,比如订单的各种状态需要造数据的情况,可以放到数据库,每次数据初始化,用完后再清理;
  • 对于邮箱配置的一些参数,可以用ini配置文件;
  • 对于全部是独立的接口项目,可以用数据驱动方式,用excel/csv管理测试的接口数据;
  • 对于少量的静态数据,比如一个接口的测试数据,也就2-3组,可以写到py脚本的开头

 

 

格式调整不好了,更规整的版本见石墨文档:https://shimo.im/docs/RWyxv9PkhwKwDwvp

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值