一.命令
pytest -v E:\lpjx-ui_test\lpjx-web-ui\testcase\web\testcases_pytest\test_login_DL_001.py::test_query_userinfo::test_login_success
执行指定用例
二.用例
1.用例执行范围:pytest.main()方法所在类当前目录及下级目录的所有用例
2.用例命名规则:
- py测试文件必须以“test_"开头(或_test结尾),方便通过文件夹执行时找到对应py文件
- 测试方法必须以test_开头
- 测试类必须以Test开头,并且不能有init方法(类名不能用小写test开头)
3.用例执行顺序:
- 默认执行顺序( pytest按照编写的测试用例顺序执行,包括py文件和py文件中用例顺序(unittest按照方法名的英文顺序执行))
- 使用pytest-ordering自定义顺序(在方法上面加上 @pytest.mark.run(order=2),注意需要安装pytest-ordering包(一般用得少),可以用pip install pytest-ordering或在安装包中安装,last最后执行,需要在pytest.ini文件markers中注册)
4.pytest配置项
- 文件名称:pytest.ini
- 文件位置:项目根目录下
- 文件类型:ini类型,如果是文本类型则不生效,需要从官网下载ini包。
- 内容:testpath,markers
难题:用例脚本在执行文件的父目录的兄弟目录的子目录下,为什么找不到用例?在执行文件的兄弟目录的子目录下就能找到用例执行??
5.用例运行级别
- 模块级(setup_module/teardown_module)开始于横块始末,全局的
- 函数级(setup_function/teardown_function)只对函数用例生效(仅非类函数生效)
- 类级(setup_class/teardown_calss)只在类中前后运行一次(在类中)
- 方法级(setup_method/teardown_method)开始于方法始末(仅类函数生效)
- 类里面的(setup/teardown)运行在调用方法前后
6.用例markers:
- @pytest.mark.skip(reason="功能未实现,暂不执行")
- @pytest.mark.skipif("len(mobile)!=11",reason="手机号不等于11位跳过") 条件为true时跳过,false不跳过
7.用例执行方式:
- pycharm执行 pytest.main()
- 命令行执行
- -m(p0 根据用例上的标签@pytest.mark.p0选择用例执行)
- -k(根据用例名称选择用例执行,部分匹配)
- -x(某一个用例执行失败,则后面用例不会执行)
- --maxfail=n(n个用例执行失败,则后面用例不会执行)
- --lf (重新运行上次失败的案例)
- --ff (重新运行所有案例,先运行失败的,再运行成功的)
- -v -s
三.参数化
fixture
1.函数简介
fixture(scope='function',params=None,autouse=False,ids=None,name=None):
- scope:有四个级别参数"function"(默认),"class","module","session"
- params:一个可选的参数列表,它将导致多个参数调用fixture功能和所有测试使用它。
- autouse:如果True,则为所有测试激活fixture func可以看到它。如果为False则显示需要参考来激活fixture
- ids:每个字符串id的列表,每个字符串对应于params这样他们就是测试ID的一部分。如果没有提供ID它们将从params自动生成
- name:fixture的名称。这默认为装饰函数的名称。如果fixture在定义它的统一模块中使用,夹具的功能名称将被请求夹具的功能arg遮蔽,解决这个问题的一种方法时将装饰函数命令"fixture_"然后使用"@pytest.fixture(name='')"
2.传参方式:
- 无参数传递
@pytest.fixture()
def before(self):
print("before")
def test_aaa(self,before):
print("aaa")
- 传元组或列表
@pytest.fixture(params=['e', 'f', 'g'])
def middle2(self, request): # request为系统默认参数
return request.param
def test_middle(self, middle2): # params传给request,调用middle,request传给middlep.request值有几个,testmiddle方法执行几次
print(middle2)
- 传字典 字典只能返回Key,输出同上元组和字典
@pytest.fixture(params={'e':1, 'f':2, 'g':3})
def middle2(self, request): # request为系统默认参数
return request.param
def test_middle(self, middle2): # params传给request,调用middle,request传给middlep.request值有几个,testmiddle方法执行几次
print(middle2)
- 传字典列表
@pytest.fixture(params=[{'e': 1, 'f': 2, 'g': 3},{"e":11,"f":22}])
def middle3(self, request):
return request.param
def test_middle3(self, middle3):
print(middle3.get("e"))
- 传csv文件方法一:
def readCsv(filePath):
res = []
with open(filePath) as csvfile:
csv_reader = csv.reader(csvfile) # 使用csv.reader读取csvfile中的文件
first = next(csv_reader) # 读取第一行每一列的标题
for row in csv_reader: # 接着从第二行开始循环读取
dd = dict(zip(first, row))
res.append(dd)
return res
@pytest.fixture(params=readCsv(r"E:\demo-selenium-pytest\data\test.csv"))
def get_csv_data(self,request): #控制每读一行,test_get_csvdata执行一次
return request.param
def test_get_csvdata(self,get_csv_data):
print(get_csv_data)
parametrize
class Test_para1:
@pytest.mark.parametrize("index_code,index_name",
[["1262", "评价#" ],
["1138", "赔款", ],
["1144","3"]])
def test_run_a(self, index_code, index_name):
print(index_code, index_name)
- 传csv文件方法二:比较好用
def readCsv2(filePath): #[['1122', '指标1'], ['1133', '指标2'], ['1144', '指标3'], ['1155', '指标4']]
res = []
if os.path.exists(filePath):
with open(filePath, encoding='GBK') as csvfile:
csv_reader = csv.reader(csvfile) # 使用csv.reader读取csvfile中的文件
next(csv_reader) #避免读第一行
for row in csv_reader: # 接着从第二行开始循环读取
res.append(row)
return res
res_success = AutoUtils.readCsv2(Const().DATA_PATH + "/DL-testdata/test_DL_01_login_012.csv")
@parameterized.parameterized.expand(res_success)
def test_login_012(self,usercode, password,flag): #flag:0 反用例, 1:正用例
self.brower = self.comm_steps.login(usercode, password)
self.comm_steps.assertEqual('检查登录用户', '1',home_page().get_usercode(self.brower), usercode)