自动化意识反思(一)-fixtrue参数化
反思背景:
- 在前文:自动化意识演变_2中使用封装configparser来提供固定参数,其中就包括token
- 每次调取登录接口获取token后,利用set方法将token更新,防止其他接口调用时出现token过期
- 每个文件或者testsuite执行时通过get方法获取配置文件中的token
发现什么问题
- 首先配置文件里面的参数应该是固定的,不能用set进行更新
- 如果是大型项目里面,token的获取方式也不是固定的(比如web端和app端共存的情况下)
- 其次每个case类都要获取token,不够精简,理应只跟mock的数据有关
产生想法
- 有一个函数能返回token
- 该函数可以作为所有调用接口的参数
- 这个函数只会执行一次,但是这一次可以针对于所有case、单个集合、单个场景case、单个case等
此时,有一个pytest的装饰器fixture可以优美的解决上面问题
pytest.fixture怎么用
- 首先看看fixture有什么用途
- 做测试前后的初始化设置,如测试数据准备,链接数据库,打开浏览器等这些操作都可以使用fixture来实现
- 测试用例的前置条件可以使用fixture实现
- fixture可以实现unittest不能实现的功能,比如unittest中的测试用例和测试用例之间是无法传递参数和数据的,但是fixture却可以解决这个问题
- 怎么构建一个fixture
fixture通过@pytest.fixture()装饰器装饰一个函数,那么这个函数就是一个fixture:
import pytest
@pytest.fixture()
def fixture():
return 'fixture'
对于单个函数来说可以这样使用:
def test_fixture(fixture):
print('我调用了{}'.format(fixture))
对于单个类来说可以这样使用:
class TestFixture(object):
def test_fixture_class(self, fixture):
print('在类中使用fixture "{}"'.format(fixture))
也可以放在外面一层调用
@pytest.mark.usefixtures('fixture')
class TestFixture(object):
def test_fixture_class(self):
print('in class with text_fixture_class')
- 怎么结合项目用
项目中用例之间会有不同的依赖,有时候整个集合需要用某个参数,或者所有用例都会使用这个参数(比如token或者sign等),这时候fixture自带scope解决了这个难题
scope参数可以是session, module,class,function; 默认为function
- session 会话级别(通常这个级别会结合conftest.py文件使用,所以后面说到conftest.py文件的时候再说)
- module 模块级别: 模块里所有的用例执行前执行一次module级别的fixture
- class 类级别 :每个类执行前都会执行一次class级别的fixture
- function :前面实例已经说了,这个默认是默认的模式,函数级别的,每个测试用例执行前都会执行一次function级别的fixture
按照级别session>module>class>function(所有用例>单个模块>单个类>单个方法)
这样一来,依赖之间就可以共存了,且可以相互调用
- 接下来进入实操
- 首先在core基础库里面新建sign.py用于返回token,很简单
import requests
import random
host = 'http://XXXX'
path = '/XXX'
phone=random.randint(14400600910,14500600000)
def sign():
url = host+path
payload = 'phone=%d'%phone
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
response = requests.request("POST", url, headers=headers, data=payload)
code, token = response.json()['code'], response.json()['token']
if code == 0:
print('获取token:'+token)
return token
else:
return token == ''
- 你可以用sign作为fixture,但是如果要做隔离,更建议是放在case里面集成fixture,因为有很多场景有依赖,是需要添加的,前面所述core是基础库,最好不要轻易动
那么就新建conftest.py(这个是一个严格命名文件),集成fixtrue。也很简单:
import pytest
from core.sign import sign
@pytest.fixture(scope='session', autouse=True)
def params():
print('开始测试')
print('开始登录')
token={'token':sign()}
yield token
print('测试结束')
- case使用fixtrue
from core.requestHandle import RequestHandle
from core.loggingHandle import LoggingHandle
import allure
from app.task_app import TaskApp
log = LoggingHandle('TestTaskPop')
Task=TaskApp()
@allure.MASTER_HELPER.feature('TaskPop')
class TestTaskPop(object):
@allure.MASTER_HELPER.story('用户信息')
def test_pop(self, params):
response = RequestHandle(Task.pop).get(params)
log.debug(response)
code = response['code']
assert code == 0
之后所有方法只要新增params参数,就可以自动调用params返回的token。
当然这是最基本的使用,在很多项目中其实单个类之间的case也会有依赖,但目前来说,一个token作为所有接口的参数差不多满足条件了