前言
- 文章比较详细,建议先收藏
- 下一步:项目的具体测试
- 有任何问题,评论区留言
单元测试目录
单元测试的目的
单元测试的由来
在软件测试的发展过程中衍生的一种测试方法,能够更高效率、更简洁地实现软件系统的模块化的测试。
单元测试的优势
- 极大程度上节约测试时间
复杂的交互场景中自动化地帮助自己测试组件,更快速的定位错误代码位置。 - 测试本身不仅是发现错误,更能预防错误
测试能够协助开发以更清晰的思路认识自己的代码问题,只有认识到代码问题才能够让代码优化,带给客户更优质的体验。 - 能够让代码更加简洁
测试后的代码,逻辑更加清晰,能够减少代码冗余。
Request模块
Request模块简介
介绍
一、说明
Request模块是一个模拟用户在客户端发送各种请求的基于HTTP协议的Python库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P8V9rGXa-1602593196197)(C:\Users\Pine\Desktop\03.png)]
二、作用
- 软件测试使用:脚本化发送请求并分析返回数据是否异常
- 爬虫使用:模拟用户脚本化自动采集网络资源
安装
# 切换虚拟环境!!! 安装镜像源为清华园
pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple
请求方式以及响应
HTTP接口动词说明
查询参数对应的request模块中的请求方式
查询参数 | 所有请求方式->requests.get(params={}) |
---|---|
请求体 json参数 | 非get请求方式(post、put、delete)->requests.post(json={}) |
请求体 form参数 | 非get请求方式(post、put、delete)->requests.post(data={}) |
参数传递方式 | requests 接收的关键参数名字 |
请求头参数 | 所有请求方式->requests.get(headers={}) |
Request模块使用(Httpbin.org)
httpbin.org说明:之后的测试案例都采用对这个网站进行请求的方案
- 作用:测试HTTP的Request请求并返回对应的Response信息,适用于GET、POST各种请求接口
- 项目架构:基于Python的Flask框架 开源
- Github地址:https://github.com/Runscope/httpbin
- 官网:http://httpbin.org/
-
Get 请求
import requests from requests import Request, Session # 1. 定义URL对象 # url = 'http://www.meiduo.site:8080/' url = 'http://httpbin.org/get' # 2. 新建request对象 注意+请求方式 response = requests.get(url) # 3. 检查获取的数据格式以及内容打印到一个文件中 with open('test1.html', 'w') as f: f.write(response.text) # 4. 可以打印response观察对象类型 print(type(response)) # text方法默认打印的返回数据的json格式 print(response1.text) # 默认打印的是返回数据二进制数据 print(response1.content) # b'{\n "args": {}, \n "headers": {\n "Accept": "*/*", \n "Accept-Encoding": "gzip, deflate", \n "Host": "httpbin.org", \n "User-Agent": "python-requests/2.23.0", \n "X-Amzn-Trace-Id": "Root=1-5f818280-636d615a13bf7f173724951b"\n }, \n "origin": "106.121.5.147", \n "url": "http://httpbin.org/get"\n}\n'
- 返回结果展示
- 返回结果展示
-
POST请求
# 1. URL URL = 'http://httpbin.org/post' # 2. request对象 json_dict = { 'user': '吴亦凡' } # 传入数据 data:表单数据 json:json数据 # response = requests.post(URL, data=json_dict) # response = requests.get(url,params=json_dict) response = requests.post(URL, json=json_dict) # 3. 写入文件 with open('test1.html', 'w', encoding='utf-8') as f: f.write(response.text)
- 返回结果
- 返回结果
-
响应对象相关属性说明
# 1.获取响应对象的数据 text(requests 会使用其推测的文本编码)->string类型 response.text # 2.获取响应对象的数据 content->bytes类型 # decode() 将 bytes-> str response.content.decode() # 3.前端返回状态码(无论数据是否验证正确,都会返回200状态码,测试判断不能用状态码) response.status_code # 4.前后端分离开发模式下,存在一个问题无论数据是否验证正确,都会返回200状态码,测试判断不能用状态码 # 测试网站登录功能,接口规定登录成功返回json->{'code':0 ,'msg':oK} # 4.1获取响应对象的 json数据---json() response.json() # 5.获取请求头信息 response.requests.headers # 6.获取响应头信息 response.headers # =====防止被反爬添加请求头的信息==== # 添加请求头信息 headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36' } request.get(url, headers=headers)
-
Cookie请求
cookie作用:1. 常用与用户登录后,登录状态信息的保存 2. 缓存一些其他信息
# ===方法1:request对象中携带cookies==== # 1. url url = 'http://httpbin.org/cookies' # 2. 定义cookie值 dict:强制类型转换 cookies = dict(cokie_is='Richerd') # 3. response加上cookie值 # response = requests.post(URL, data=cookies) response = requests.get(url, cookies=cookies) # print(response.text) # 4. 写入文件 with open('test1.html', 'w', encoding='utf-8') as f: f.write(response.text) # ===方法2: 直接使用cookie中的RequestsCookieJar()=== # 这里引入 request.cookie # 1.实例化cookie_jar对象 jar = requests.cookies.RequestsCookieJar() # 2.设置cookie # jar.set(请求头key值, value值, 域名, 路径) jar.set('coo', 'zhenxiang', domain='httpbin.org', path='/cookies') # 3.url url = 'http://httpbin.org/cookies' # 4.获取对象 response = requests.get(url, cookies=jar) print(response.text)
-
Session请求
seesion作用:和cookie类似用于保存一些信息,但浏览器中往往存的是seesionid值,真正的session信息存储在数据库中
request模块中Session和Cookie的请求登录的区分
- request.get()
requests.get() 就可以发送请求, 但是 遇到涉及登录的时候, 应该先发送登录请求->登录成功获取cookies->可以去请求需要登录认证的页面
* 1.login请求: 携带账户和密码 response = requests.post(url, json=xxx) * 2.解析登录成功的:cookie = response.request._cookies * 3.登录用户中心请求 '/mytaobao...':requests.get('<https://i.taobao.com/my_taobao.htm?spm=xxxx', cookies=cookies)
- session.get()
- 1.先访问的是login的请求-- 携带账户和密码 response = session.post()
- 2.再发送 info 请求 – session.get(‘info’)
from requests import Session # 1.创建session对象 s = Session() # 2.发送带cookie的请求 用url设置一个cookie值 之后的cookie将会一直和session对象绑定 s.get('http://httpbin.org/cookies/set/sessioncookie/123456789') # 3.获取cookie值 检查是否获取成功 r = s.get("http://httpbin.org/cookies") print(r.text) # 1. 设置 用户名和密码 即设置session对象的auth属性默认值 s.auth = ('user', 'pass') # 2. 可以直接增加请求头中信息(在原有请求头字段中添加) s.headers.update({ 'test1': 'wangyibo'}) # 3. 请求头中再次以参数形式添加另一个请求头信息 并检查请求头中是否已经添加成功 # 注意这里或默认auth之前添加的信息也会一块合并到请求头中 r = s.get('http://httpbin.org/headers', headers={ 'test2': 'yibowangzha'}) print(r.text)
- 返回结果
Django单元测试
注意!:Django每次测试每次测试之前会自动创建一个和项目默认数据库名称相同的default临时数据库,而且临时数据库是复制了项目所有的表但是没有数据,测试用例测试结束后,会把临时创建的default数据库删除
说明
- Django的单元测试模块继承自Python自带的测试基类unittest
- postman和unitest的区别
- Postman适用于接口测试 —>黑盒测试
- unitest适用于代码逻辑测试 —>白盒测试
数据库环境准备
在Django的settings配置文件中进行对测试数据库配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': 'root',
'PASSWORD': 'mysql',
'NAME': 'mysql',
'OPTION': {
'charset': 'utf8'},
# 配置测试的数据库
# 1.单元测试需要使用的数据库,测试执行时,会自动创建新的default数据库包含TEST库
# 2.每次自动创建的数据库中没有测试数据,而且测试执行完会自动删除测试数据库
# 3.如果和default配置相同,使用默认配置
'TEST':{
'NAME':'test',
'CHARSET': 'utf8', # 设置测试数据库的字符集
'COLLATION': 'utf8_general_ci', # 测试数据表中的行的编码
},
},
}
Testcase
注意事项!!!
- 由于使用的是Django自带的测试模块,所以所有的测试代码都必须在项目的目录下,且为Python的package
- 创建的测试函数函数名组成格式 test_xxx
- 执行方式为终端执行 python manage.py test 默认一键执行所有的测试代码
- 执行摸个应用的测试 python manage.py 应用名
- 执行应用下的某个测试文件 python manage.py 应用名.test_xxx
- 执行应用下测试文件中的具体测试类 python manage.py 应用名.test_xxx.Demotest
- 具体到函数 执行应用下测试文件中的具体测试类 python manage.py 应用名.test_xxx.Demotest.test_xxx
setUp和tearDown函数
-
setUp tearDown
setUp 和 tearDown函数作用就是在测试用例代码执行前/后 做一些准备动作 !!!每个测试用例执行前后都会执行
使用场景:测试之前打开文件 测试之后关闭文件
class TestDemo(TestCase): def setUp(self): print('---setup---') def tearDown(self) -> None: print('---tearDown---\n') def test_two(self): print('---222---') def test_three(self): print('---3333---') def test_four(self): print('---4444---') class TestDemo2(TestCase): def test_two(self): print('\n---TestDemo---')
测试结果:
---setup--- ---4444--- ---tearDown--- ---setup--- ---3333--- ---tearDown--- ---setup--- ---222--- ---tearDown--- ---TestDemo---
-
@classmthod修饰
setUpclass 和 tearDownclass 函数在这个类中的所有测试用例执行前后只会执行一次
使用场景:测试用例测试之前数据库中添加测试数据
class ThreeTest(TestCase): @classmethod def setUpClass(cls): print('setUpClass--每个测试用例类---调用一次') @classmethod def tearDownClass(cls): print('tearDownClass---每个测试用例类---调用一次') def test_baidu(self): url = 'http://www.baidu.com' response = requests.get(url) print(response.status_code) def test_tencent(self): url = 'http://www.tencent.com' response = requests.get(url) print(response.status_code)
返回结果:
setUpClass--每个测试用例类---调用一次 200 200 tearDownClass---每个测试用例类---调用一次
-
登录测试
class LoginTest(TestCase): def test_login(self): url = 'http://www.heiheihei.site:8000/login/' json_dict = { 'username': 'wangyibo', 'password': '12345678'} response = requests.post(url, json=json_dict) print(response.content.decode()) # 登录成功返回json字符串 { "code": 0, "errmsg": "ok"}
assert断言捕获异常的方法