一、概述1. 课程概述2. 课程安排二、接口测试1.【知道】什么是接口测试2. 环境准备3. Postman的基本使用3.1【掌握】借助Postman完成接口测试3.2【掌握】导出导入Postman测试记录4. Requests的使用4.1 发送GET请求4.1.1【掌握】发送GET请求4.1.2【掌握】响应状态码、响应头、响应体4.1.3【知道】字符编码4.1.4【掌握】resp.json4.1.5【知道】构造请求头和cookies4.2【掌握】发送POST请求4.3【掌握】requests和requests.session的区别三、基于django的单元测试1.【知道】认识单元测试2.【掌握】编写和运行django的单元测试3. TestCase类3.1【知道】前后置方法运行特点3.2【掌握】setUpClass 和 tearDownClass应用场景4. Client类4.1 Client介绍4.2【知道】Client的使用4.3 测试django自带的用户验证系统5. 断言5.1【知道】断言介绍5.2【掌握】断言的使用
一、概述
1. 课程概述
2. 课程安排
二、接口测试
1.【知道】什么是接口测试
2. 环境准备
-
创建虚拟环境
-
下载模块
-
运行项目代码
3. Postman的基本使用
3.1【掌握】借助Postman完成接口测试
json格式数据如何发送
3.2【掌握】导出导入Postman测试记录
4. Requests的使用
-
Requests是一个功能强大的HTTP Client,能够帮助我们发送HTTP请求,并获取响应
4.1 发送GET请求
4.1.1【掌握】发送GET请求
import requests
url = 'http://127.0.0.1:8080/user'
# 响应对象 = requests.get(url)
resp = requests.get(url)
print(resp.text)
4.1.2【掌握】响应状态码、响应头、响应体
# 响应状态码、响应头、响应体
print(resp.status_code) # 401
print(resp.headers) # 响应头
print(resp.text, type(resp.text)) # {"error": "用户未登录"} <class 'str'>
print(resp.content) # 二进制
print(resp.json()) # 是字典类型,如果返回的格式不是json,发生异常, JSONDecodeError
4.1.3【知道】字符编码
# 查看编码
print(resp.encoding) # ISO-8859-1
# 显示中文,修改编码格式为utf-8
resp.encoding = 'utf-8'
4.1.4【掌握】resp.json
print(resp.json()) # 是字典类型,如果返回的格式不是json,发生异常, JSONDecodeError
4.1.5【知道】构造请求头和cookies
# 构造header
_headers = {'User-Agent':'hello mike'}
resp = requests.get(url, headers=_headers)
print(resp.text) # {"User-Agent": "hello mike", "Cookies": {}}
_cookies = {
'k1':'v1',
'k2':'v2'
}
resp = requests.get(url, headers=_headers, cookies=_cookies)
print(resp.text)
4.2【掌握】发送POST请求
import requests
# 如果以表单格式提交数据,使用data关键字参数
# 如果以json格式提交数据,使用json关键字参数
# 构建用户登陆数据
user_info = {
'username':'mike123',
'password':'12345678'
}
# 发送Post请求
resp = requests.post('http://127.0.0.1:8080/login', data=user_info)
# 获取响应内容
print(resp.json())
4.3【掌握】requests和requests.session的区别
-
requests不会状态保持
-
requests.session可以状态保持
import requests
# 实例化一个 requests.Session() 对象
# session对象发送数据,发送请求方式和requests一样
session = requests.Session()
# 登陆
login_url = 'http://127.0.0.1:8080/login'
# 构建用户登陆数据
user_info = {
'username':'mike123',
'password':'12345678'
}
resp = session.post(login_url, data=user_info)
print(resp.json())
# 获取登陆用户的信息
resp = session.get("http://127.0.0.1:8080/user")
print(resp.json())
三、基于django的单元测试
1.【知道】认识单元测试
-
单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。
-
单元测试侧重于代码逻辑,接口测试侧重于业务逻辑
2.【掌握】编写和运行django的单元测试
-
写的代码集成在项目代码中,创建test开头的文件
-
类继承
django.test.TestCase
from django.test import TestCase
class MyTestCase(TestCase):
# 1. 前置、后置方法,名字固定
def setUp(self) -> None:
print('前置setUp2')
def tearDown(self) -> None:
print('后置tearDown2')
# 2. 测试用例,test开头的方法
def test_1(self):
print('测试用例12')
def test_2(self):
print('测试用例22') -
命令运行
# 执行项目中全部的测试用例,项目中所有以test开头的py文件都会执行 python manage.py test # 运行某个名为users的app下面的所有的测试用例,users是应用的名字(APP_name),应用中所有以test开头的py文件都会执行 python manage.py test users # 运行某个app下面的tests.py文件 python manage.py test users.tests # 运行某个app下面的tests.py文件中指定的class类 python manage.py test users.tests.MyClassTestCase # 执行ModeTest类下的某个测试方法 python manage.py test users.tests.MyClassTestCase.test_my_func
3. TestCase类
3.1【知道】前后置方法运行特点
-
类方法的前后置方法:在类启动、结束调用
-
实例前后置方法:test开头的实例方法前后调用
from django.test import TestCase class MyTestCase(TestCase): # 1. 前置、后置方法,名字固定 # 针对于test开头的实例方法 def setUp(self) -> None: print('前置setUp ') def tearDown(self) -> None: print('后置tearDown ') @classmethod def setUpClass(cls): print('类方法setUpClass') @classmethod def tearDownClass(cls): print('类方法tearDownClass') # 2. 测试用例,test开头的方法 def test_1(self): print('测试用例1') def test_2(self): print('测试用例2')
3.2【掌握】setUpClass 和 tearDownClass应用场景
# 定义 setUpClass: 用户登录 # 定义 tearDownClass: 用户退出 # 定义测试方法:获取登陆用户、查看UA和Cookie from django.test import TestCase from requests import Session class DjangoTest(TestCase): # 定义 setUpClass: 用户登录 @classmethod def setUpClass(cls): # 实例化对象, cls.session类属性 cls.session = Session() # 登陆 login_url = 'http://127.0.0.1:8080/login' # 构建用户登陆数据 user_info = { 'username': 'mike123', 'password': '12345678' } resp = cls.session.post(login_url, data=user_info) print("登陆", resp.json()) # 定义 tearDownClass: 用户退出 @classmethod def tearDownClass(cls): resp = cls.session.get('http://127.0.0.1:8080/logout') print("登出", resp.json()) # 查看用户信息 def test_user(self): resp = self.session.get('http://127.0.0.1:8080/user') print("用户信息", resp.json()) # 查看cookies def test_header(self): resp = self.session.get('http://127.0.0.1:8080/header') print("头部信息", resp.json())
4. Client类
4.1 Client介绍
-
使用和requests.session一样
-
可以状态保持
-
不用启动服务也可以使用,数据不会保存在数据库,放在临时的数据库
4.2【知道】Client的使用
-
虽然不用启动后台服务,但是依赖于后台代码,所以,接口协议按照后台的规定
-
由于没有启动服务,所以,不需要url
-
其它用法和requests.Session用法一样
# 注册 # 登录 # 查看UA和Cookie # 登出 # 再次查看UA和Cookie from django.test import TestCase, Client class DjangoTest(TestCase): def setUp(self) -> None: print('setUp') # 共享实例属性的数据 self.user_info = { 'username': 'mike123', 'password': '12345678', 'mobile': '13344445555' } # 实例化client对象 self.client = Client() def test_api(self): print('注册、登陆、查看、退出、查看') self.do_register() self.do_login() self.do_header() self.do_logout() self.do_header() def do_register(self): print('注册') resp = self.client.post('/register', data=self.user_info) print(resp.json()) def do_login(self): print('登陆') resp = self.client.post('/login', data=self.user_info) print(resp.json()) def do_header(self): print('查看') resp = self.client.get('/header') print(resp.json()) def do_logout(self): print('登出') resp = self.client.get('/logout') print(resp.json())
4.3 测试django自带的用户验证系统
def do_login(self): print('登陆') # 项目使用django自带的用户验证系统,可用login函数和logout函数进行测试 resp = self.client.login(username=self.user_info['username'], password=self.user_info['password']) print(resp) def do_logout(self): print('登出') self.client.logout()
5. 断言
5.1【知道】断言介绍
-
测试结果是否符合预期,如果符合,说明测试通过(断言成功),如果不符合测试失败(断言失败)
# 检查是否登录成功 if result_code != 200: # 只要状态码不是200,说明登陆失败,不符合预期,抛出断言异常 raise AssertionError(f"实际的结果是{result_code},预期的结果是:200")
5.2【掌握】断言的使用
# 如果result_code和200相同,说明符合预期,测试通过,msg不会显示 # 否则,测试不通过,msg显示 self.assertEqual(result_code, 200, msg='状态玛不为200,测试不通过')
1. Pytest介绍2.【掌握】Pytest 第一个例子3. 断言的处理3.1【掌握】assert断言语句3.2 异常断言3.2.1【掌握】pytest.raises()的使用3.2.2【知道】把异常信息存储到变量3.2.3 通过异常的内容捕捉异常3.3 警告断言3.3.1【掌握】pytest.warns()的使用3.3.2【知道】把警告信息存储到变量3.3.3 通过警告的内容捕捉警告4. setup和teardown函数4.1【知道】函数级别4.2【知道】类级别4.3【知道】模块级别5. pytest.fixture基本使用5.1【理解】fixture基本使用5.2【掌握】fixture装饰的函数5.3 conftest.py文件5.3.1【掌握】共享fixture函数5.3.2【掌握】pytest.mark.usefixtures6. pytest.fixture参数6.1【知道】scope参数6.2 params参数6.2.1【理解】案例16.2.2【理解】案例26.3【知道】autouse参数7. pytest.mark标记7.1【知道】pytest.mark.xfail()7.2【知道】pytest.mark.skip()7.3【知道】pytest.mark.skipif()7.4【知道】pytest.mark.parametrize()
1. Pytest介绍
-
默认自动识别当天目录下test开头的函数和方法、Test开头的类
import pytest
import requests
# 定义2个test开头的函数
def test_one():
print('test_one')
def test_two():
print('test_two')
# 定义一个Test开头的类
class TestClass(object):
# 定义2个test开头的实例方法
def test_1(self):
print('11111111111111111111111')
def test_2(self):
print('222222222222222')
if __name__ == '__main__':
# pytest.main() # 默认允许同一个目录下,test开头的文件,默认不支持打印,需要配置才能打印
# pytest.main(['-s']) # -s, 可以打印
pytest.main(['-s', 'test_1.py'])
-
pytest自动失败test开头的函数和方法,或者Test开头的类
pytest.main() # 不打印运行同目录所有test文件
pytest.main(['-s']) # 可以打印
pytest.main(['-s', 'test_1.py']) # 只运行test_1.py文件 -
命令行运行
-
pytest
-
会执行当前文件的同时,路径下所有以test开头的py文件都会被执行
-
pytest先获取所有文件中的测试函数后,再执行
-
-
不会显示代码中的标准输出(print、logging)
-
-
pytest -s
-
会执行当前文件的同时,路径下所有以test开头的py文件都会被执行
-
pytest先获取所有文件中的测试函数后,再执行
-
-
显示代码中的标准输出(print、logging)
-
-
pytest test_1.py
-
只会执行当前文件
-
不会显示代码中的标准输出(print、logging)
-
-
pytest -s test_1.py
-
只会执行当前文件
-
显示代码中的标准输出(print、logging)
-
3. 断言的处理
3.1【掌握】assert断言语句
# django自带断言 resp.status_code, 200, msg=‘提示信息’
# assert 条件表达式, ’提示信息‘
assert resp.status_code == 200, '测试不通过,状态码不是200'
3.2 异常断言
3.2.1【掌握】pytest.raises()的使用
"""
# 产生的异常和预期要捕获到的异常一样,则测试通过
with pytest.raises(预期要捕获到的异常):
产生的异常
"""
class TestAssert(object):
def test_assert(self):
with pytest.raises(TypeError):
is_leap_year("2020")
3.2.2【知道】把异常信息存储到变量
def test_assert2(self):
with pytest.raises(TypeError) as err_info:
is_leap_year("2020")
err_info.__dict__ # 查看对象内部成员信息
assert err_info.type==TypeError, '捕获到的异常不匹配'
3.2.3 通过异常的内容捕捉异常
# 通过异常提示信息捕获指定异常
with pytest.raises(BaseException, match='不是整数') as err_info:
is_leap_year("2020")
if err_info.type == TypeError:
print('aaaaaaaaaaa')
3.3 警告断言
-
捕获警告,捕获到警告,测试通过
-
可以同时捕获多个警告
3.3.1【掌握】pytest.warns()的使用
3.3.2【知道】把警告信息存储到变量
class TestWarn(object):
def test_1(self):
with pytest.warns(UserWarning):
warnings.warn("value must be 0 or None", UserWarning)
def test_2(self):
# 由于捕获了2个警告,warn_info就是列表
with pytest.warns((UserWarning, RuntimeWarning)) as warn_info:
warnings.warn("value must be 0 or None", UserWarning)
warnings.warn("value must11111", RuntimeWarning)
# print(warn_info.__dict__)
print(len(warn_info))
# {'message': UserWarning('value must be 0 or None',),
# 'category': <class 'UserWarning'>, 'filename': '/home/python/code/pytest_code/test_4_warn.py', 'lineno': 25, 'file': None, 'line': None, 'source': None, '_category_name': 'UserWarning'}
print(warn_info[0].__dict__)
print(warn_info[0].message)
print(warn_info[0].category)
3.3.3 通过警告的内容捕捉警告
>> > with warns(UserWarning, match='must be 0 or None'):
...
warnings.warn("value must be 0 or None", UserWarning)
>> > with warns(UserWarning, match=r'must be d+$'):
...
warnings.warn("value must be 42", UserWarning)
>> > with warns(UserWarning, match=r'must be d+$'):
...
warnings.warn("this is not here", UserWarning)
4. setup和teardown函数
4.1【知道】函数级别
# 函数级别的前、后置函数,只针对普通测试用例 def setup_function(): print('setup_function') def teardown_function(): print('teardown_function') def test_1(): print('普通测试用例111111') def test_2(): print('普通测试用例111111') class TestClass(object): def test_one(self): print('类实例方法测试用例111111')
4.2【知道】类级别
class TestClass(object): # 针对类的前置后置方法 @classmethod def setup_class(cls): print('setup_class') @classmethod def teardown_class(cls): print('teardown_class') # 针对测试实例方法 def setup_method(self): print('setup_method') def teardown_method(self): print('setup_method') def test_one(self): print('类实例方法测试用例111111') def test_two(self): print('类实例方法测试用例22222')
-
类的前置后置方法:在类启动、结束运行
-
测试实例方法:类中测试实例方法调用前、调用结束运行
4.3【知道】模块级别
# 针对模块 def setup_module(): print('setup_module') def teardown_module(): print('teardown_module') # 针对普通测试函数 def setup_function(): print('setup_function') def teardown_function(): print('teardown_function') def test_1(): print('普通测试用例111111') def test_2(): print('普通测试用例22222') class TestClass(object): # 针对类的前置后置方法 @classmethod def setup_class(cls): print('setup_class') @classmethod def teardown_class(cls): print('teardown_class') # 针对测试实例方法 def setup_method(self): print('setup_method') def teardown_method(self): print('teardown_method') def test_one(self): print('类实例方法测试用例111111') def test_two(self): print('类实例方法测试用例22222')
运行结果:
test_8.py setup_module setup_function 普通测试用例111111 .teardown_function setup_function 普通测试用例22222 .teardown_function setup_class setup_method 类实例方法测试用例111111 .teardown_method setup_method 类实例方法测试用例22222 .teardown_method teardown_class teardown_module
5. pytest.fixture基本使用
5.1【理解】fixture基本使用
# 0.@pytest.fixture装饰函数 @pytest.fixture() def get_web_url(): print('get_web_url') return 'http://www.baidu.com' # 1. 把上面函数名作为测试用例的参数 def test_web(get_web_url): # 2. 测试用例调用前,需要先确定形参get_web_url,就是调用get_web_url print('test_web') print(get_web_url) # 测试用例内部使用get_web_url,就是使用它返回值 r = requests.get(get_web_url) assert r.status_code == 200, '测试失败'
5.2【掌握】fixture装饰的函数
@pytest.fixture() def foo(): print(' foo: 1111111111111') return 'http://itcast.cn' @pytest.fixture() def bar(foo): resp = requests.get(foo) print('bar: 22222222222222') return resp def test_web(bar): print('333333333333') # 响应状态码应该是200, 否则会断言失败 assert bar.status_code == 200 if __name__ == '__main__': pytest.main(['-s', 'test_10.py'])
5.3 conftest.py文件
5.3.1【掌握】共享fixture函数
5.3.2【掌握】pytest.mark.usefixtures
6. pytest.fixture参数
6.1【知道】scope参数
-
function:设置为function,表示每个测试方法都要执行一次, 普通测试用例、类里面的测试用例都可以执行
-
class
# 普通测试方法,正常执行,类里面的测试实例方法,只会执行1一次 import pytest @pytest.fixture(scope='class') def foo(): print('foo') def test_1(foo): print('普通测试用例111111') def test_2(foo): print('普通测试用例22222') class TestClass(object): def test_one(self, foo): print('类实例方法测试用例111111') def test_two(self, foo): print('类实例方法测试用例22222')
# module:只会在传参的时候执行1次,针对test开头的文件 # session:只会在session开始的时候执行1次,在一个文件夹启动所有测试文件,session是整个文件夹 import pytest # @pytest.fixture(scope='module') @pytest.fixture(scope='session') def foo(): print('foo') def test_1(foo): print('普通测试用例111111') def test_2(foo): print('普通测试用例22222') class TestClass(object): def test_one(self, foo): print('类实例方法测试用例111111') def test_two(self, foo): print('类实例方法测试用例22222')
6.2 params参数
6.2.1【理解】案例1
import pytest def check_password(password): """ 检查密码是否合法 :param password: 长度是 8 到 16 :return: """ pwd_len = len(password) if pwd_len < 8: return False elif pwd_len > 16: return False else: return True # 参数化 @pytest.fixture(params=['1234', '1312532532', '1325215', '135325']) def get_pwd(request): # request固定 return request.param # 测试用例 def test_pwd_len(get_pwd): print(get_pwd) print(check_password(get_pwd))
6.2.2【理解】案例2
import pytest # 参数化 @pytest.fixture(params=['mike123', 'mike666', 'admin12']) def get_user(request): # request固定 return request.param @pytest.fixture(params=['12345678', 'mike66611', 'admin1211']) def get_pwd(request): # request固定 return request.param # 测试用例 def test_login(get_user, get_pwd): print(get_user, ' ===> ', get_pwd)
test_15.py mike123 ===> 12345678 .mike123 ===> mike66611 .mike123 ===> admin1211 .mike666 ===> 12345678 .mike666 ===> mike66611 .mike666 ===> admin1211 .admin12 ===> 12345678 .admin12 ===> mike66611 .admin12 ===> admin1211
6.3【知道】autouse参数
import pytest # autouse=True, 当前所有测试用例前调用一次 @pytest.fixture(autouse=True) def foo(): print('foo') def test_1(): print('普通测试用例111111') def test_2(): print('普通测试用例22222') class TestClass(object): def test_one(self): print('类实例方法测试用例111111') def test_two(self): print('类实例方法测试用例22222')
7. pytest.mark标记
7.1【知道】pytest.mark.xfail()
# 写了condition后,需要写上reason # @pytest.mark.xfail(condition=True, reason='标志失效') # @pytest.mark.xfail(condition=False, reason='标志失效') # False,相当于没有写这句话 # @pytest.mark.xfail(condition=True, reason='标志失效', raises=TypeError) @pytest.mark.xfail(reason='标志失效') def test_1(): print(' 普通测试用例111111 ')
7.2【知道】pytest.mark.skip()
7.3【知道】pytest.mark.skipif()
# 修饰的测试用例,跳过,不执行 @pytest.mark.skip(reason='跳过,不执行') def test_1(): print(' 普通测试用例111111 ') def test_2(): print(' 普通测试用例22222 ') # True跳过,False执行 @pytest.mark.skipif(condition=False,reason='跳过,不执行') def test_3(): print(' 普通测试用例333333 ')
7.4【知道】pytest.mark.parametrize()
import pytest @pytest.mark.parametrize('num', [1, 2, 3, 4]) def test_get_num(num): print(num) @pytest.mark.parametrize(['user', 'pwd'],[('mike123', '12345678'), ('hello11', 'hdshghadshg'), ('aaaaa', 'aaaaaddd')]) def test_login(user, pwd): print(user, pwd)
test_19.py 1 .2 .3 .4 .mike123 12345678 .hello11 hdshghadshg .aaaaa aaaaaddd
一、pytest(下)1. pytest配置文件1.1【知道】配置pytest命令行运行参数1.2【知道】配置文件参数详解2. pytest常用插件2.1【掌握】生成测试报告2.2【知道】控制函数执行顺序插件2.3 失败重试2.4 按名称取消插件3. Yaml3.1【知道】Yaml语法格式3.2 Python处理yaml文件3.2.1【掌握】读取yaml文件3.2.2【掌握】写入文件内容4. 综合案例4.1【理解】测试目录结构4.2【掌握】公用方法类:读取yaml数据4.3【掌握】公用方法类:请求封装4.4【掌握】注册单元测试用例4.5【掌握】登陆单元测试用例
一、pytest(下)
1. pytest配置文件
1.1【知道】配置pytest命令行运行参数
-
addopts:指定运行的文件,如果配置文件指定了运行的文件,代码中不建议指定运行文件
-
如果目录中嵌套背的代码目录,这个目录建议新建一个
__init__.py
文件
[pytest]
;addopts = -s test_18.py test_19.py ;注释
addopts = -s
[pytest]
;addopts = -s test_18.py test_19.py ;注释,占一行
addopts = -s
;识别目录 tests
testpaths = ./tests
python_files = test*.py
python_classes = Test*
python_functions = test*
具体参数解读
-
addopts - 配置pytest命令行运行参数
-
空格分隔,可添加多个命令行参数
-
-
testpaths - 配置测试搜索的路径
-
当前目录下的测试脚本文件夹 可自定义
-
-
python_files - 配置测试搜索的文件名
-
当前目录下的测试脚本文件夹下,以
test_
开头,以.py
结尾的所有文件 可自定义
-
-
python_classes - 配置测试搜索的测试类名
-
当前目录下的测试脚本文件夹下,以
Test_
开头的类 可自定义
-
-
配置测试搜索的测试函数名
-
当前目录下的测试脚本文件夹下,以
test_
开头的⽅法 可自定义
-
2. pytest常用插件
2.1【掌握】生成测试报告
-
需要先按照插件:
pip install pytest-html # 生成测试报告
-
运行命令:
pytest -s 测试用例文件 --html=./报告名字.html
2.2【知道】控制函数执行顺序插件
-
安装插件:
pip install pytest-ordering
-
order=1, 数字小的先运行
import pytest
class Test_ABC:
def setup_class(self):
print("setup_class")
def teardown_class(self):
print("teardown_class")
2.3 失败重试
-
pip install pytest-rerunfailures
-
命令:
--reruns 重来次数
-
失败重试,重新开始,只重试测试用例失败的例子
2.4 按名称取消插件
-
-p no:ordering -p no:html -p no:rerunfailures
3. Yaml
3.1【知道】Yaml语法格式
3.2 Python处理yaml文件
-
pip3 install -U PyYAML
3.2.1【掌握】读取yaml文件
import yaml
def test_read():
# 1. 打开文件, 文件对象
# 2. 返回数据 = yaml.load(文件对象)
with open('./xxx.yaml', 'r') as f:
data = yaml.load(f, Loader=yaml.FullLoader)
print(data)
3.2.2【掌握】写入文件内容
import yaml
data={'Search_Data': {
'search_test_002': {'expect': {'value': '你好'}, 'value': '你好'},
'search_test_001': {'expect': [4, 5, 6], 'value': 456}
}
}
# 1. 只写方式打开文件,制定utf-8编码,返回文件对象
# 2. yaml.dump(数据,文件对象, allow_unicode=True)
def test_write():
with open('yyy.yaml', 'w', encoding='utf-8') as f:
yaml.dump(data, f, allow_unicode = True)
4. 综合案例
4.1【理解】测试目录结构
测试目录结构:
数据准备:
pytest.ini:
[pytest]
addopts = -s --html=report/report.html
testpaths = ./tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
server.yaml:
schema
register.ymal:
url
login.yaml:
url: '/login' user1: username: 'admin11' password: '12345678' user2: username: 'admin22' password: '12345678' user3: username: 'admin33' password: '12345678'
login_logout.yaml:
url: '/login' user1: username: 'admin11' password: '12345678'
4.2【掌握】公用方法类:读取yaml数据
# 1. 封装接口,传入文件名,自动返回读取到的文件信息 # 2. 内部处理路径 import os import yaml class Data(object): # 类属性,获取project的绝对路径 # os.path.dirname()返回去掉文件名后返回的绝对路径 # os.path.abspath(__file__) 当前文件的绝对路径 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @classmethod def read_yaml(cls, file_name): # 拼接路径 /home/python/code/pytest_project file_path = os.path.join(cls.BASE_DIR, 'data', file_name) print(file_path) # 打开文件 with open(file_path, 'r') as f: # 读取内容 data = yaml.load(f, Loader=yaml.FullLoader) return data # print(Data.BASE_DIR) # print(Data.read_yaml('server.yaml')) # print(Data.read_yaml('users/register.yaml'))
4.3【掌握】公用方法类:请求封装
""" 1. 获取服务器的信息,读取文件,拆包 2. 封装get请求,post请求 """ # 从哪里运行,从哪里开始导包 from pytest_project.utils.data import Data import requests class Ask(object): @staticmethod def get_url(): """http://locast:8080""" # { schema: 'http', host: 'localhost', port: 8080 } server = Data.read_yaml('server.yaml') return f"{server['schema']}://{server['host']}:{server['port']}" @classmethod def get(cls, path): """ :param path: 路径参数, /register :return: 响应对象 """ resp = requests.get(cls.get_url()+path) return resp @classmethod def post(cls, path, data=None, json=None): """ :param path: 路径参数, /register :return: 响应对象 """ resp = requests.post(cls.get_url()+path, data=data, json=json) return resp
4.4【掌握】注册单元测试用例
import pytest from pytest_project.utils.ask import Ask from pytest_project.utils.data import Data """ 1. 读取配置文件的信息,提取用户信息 2. 组包 [(url, {注册信息}), (url, {注册信息}), (url, {注册信息})] [('/register', {注册信息1}), ('/register', {注册信息2}), ('/register', {注册信息3})] """ def get_regiter_info(): users_info = Data.read_user_yaml('register.yaml') # print(users_info) args_list = [] for k, v in users_info.items(): if k != 'url': args_list.append((users_info['url'], v)) # print(args_list) return args_list class TestUsers(object): @pytest.mark.skipif(condition=True, reason='注册跳过哦') @pytest.mark.parametrize(['url', 'user_info'], get_regiter_info()) def test_register(self, url, user_info): resp = Ask.post(url, data=user_info) print(resp.json()) assert resp.status_code == 200, '注册失败'
4.5【掌握】登陆单元测试用例
import pytest from pytest_project.utils.ask import Ask from pytest_project.utils.data import Data """ 1. 读取配置文件的信息,提取用户信息 2. 组包 [(url, {注册信息}), (url, {注册信息}), (url, {注册信息})] [('/register', {注册信息1}), ('/register', {注册信息2}), ('/register', {注册信息3})] """ def get_register_info(): users_info = Data.read_user_yaml('register.yaml') # print(users_info) args_list = [] for k, v in users_info.items(): if k != 'url': args_list.append((users_info['url'], v)) # print(args_list) return args_list def get_login_info(): users_info = Data.read_user_yaml('login.yaml') # print(users_info) args_list = [] for k, v in users_info.items(): if k != 'url': args_list.append((users_info['url'], v)) # print(args_list) return args_list class TestUsers(object): @pytest.mark.skipif(condition=True, reason='注册跳过哦') @pytest.mark.parametrize(['url', 'user_info'], get_register_info()) def test_register(self, url, user_info): resp = Ask.post(url, data=user_info) print(resp.json()) assert resp.status_code == 200, '注册失败' @pytest.mark.skipif(condition=False, reason='登陆跳过哦') @pytest.mark.parametrize(['url', 'user_info'], get_login_info()) def test_login(self, url, user_info): resp = Ask.post(url, data=user_info) print(resp.json()) assert resp.status_code == 200, '登陆失败'