一、pytest测试用例编写规则:
- 文件以test_开头或者_test结尾
- 类名以Test开头
- 方法/函数名以test_开头
- 注意:测试类中不可以添加 __init__构造函数
二、pycharm设置默认执行器为pytest:
- setting->Tools->Python Intergrated Tools
- Default test runner:pytest
三、运行多条用例:
- 执行包下所有的用例:pytest/py.test [包名]
- 执行单独一个pytest模块: pytest 文件名.py
- 运行某个单独模块里面某个类:pytest 文件名.py::类名
- 运行某个模块里面某个类里面的方法:pytest 文件名.py::类名::方法名:
四、测试装置介绍
- 全局模块级: setup_module/teardown_module
- 类级,只在类中前后运行一次: setup_class/teardown_class
- 函数级,在类外: setup_function/teardown_funnction
- 方法级,类中的每个方法执行前后: setup_method/teardown_method
- 在类中,运行在调用方法的前后: setup/teardown_class
五、pytest常用命令行参数
- –help
- -x 用例一旦失败(fail/error),就立刻停止执行
- –maxfail=num 失败用例达到多少条终止测试
- -m 标记用例
- -k 执行包含某个关键字的测试用例
- -v 打印详细日志
- -s 打印输出日志(一般-vs一起使用)
- –collect-only (测试平台,pytest 自动导入功能)
- –lf (–last-failed) 只重新运行故障
- –ff (–failed-first) 先运行故障然后再运行其余的测试
六、mark标记测试用例
- mark标记测试用例
- 场景:只执行符合要求的某一部分用例,可以把一个web项目划分多个模块,然后指定木块名称执行。
- 解决:在测试用例方法上加@pytest.mark.标签名
- 执行:-m执行自定义标记的相关用例
- pytest -s test_mark.py -m=webtest
- pytest -s test_mark.py -m apptest
- pytest -s test_mark.py -m “not ios”
-
跳过(skip)及预期失败(xFail)
- 这是pytest的内置标签,可以处理一些特殊的测试用例——不能成功的测试用例
- skip - 始终跳过改测试用例
- skipif - 遇到特定情况跳过该测试用例
- xfail - 遇到特定情况,产生一个“期望失败”的输出
-
skip使用场景
- 调试时不想运行这个用例
- 标记无法在某些平台上运行的测试功能
- 在某些版本中执行,其他版本中跳过
- 比如:当前的外部资源不可用时跳过
- 如果测试数据时从数据库中渠道的
- 连接数据库的功能如果返回结果未成功就跳过,因为执行也会报错
- 解决1:添加装饰器
@pytest.mark.skip @pytest.mark.skipif - 解决2:代码中添加跳过代码
-
xfail 使用场景
- 与skip类似,预期结果未fail,标记用例未fail
- 用法:添加装饰器
@pytest.mark.xfail -
参数化
- 参数化设计方法就是将模型中的定量信息变量化,使之成为任意调整的参数。
- 对于变量化参数赋予不同数值,就可得到不同大小和形状的零件模型。
-
mark-参数化测试函数
- 测试场景
- 测试登录成功,登录失败(账号错误,密码错误)
- 创建多种账号:中文账号,英文账号
- 普通测试用例方法
- Copy多份代码或者读入参数
- 一次性执行多个输入参数
- pyetst参数化实现方法
@pytest.mark.parametrize 进行参数化和数据驱动,更灵活 -
mark:参数化测试函数的使用
-
单参数 search_list = ['appium', 'selenium', 'pytest']
@pytest.mark.parametrize('name', search_list)
def test_search(name):
assert name in search_list
-
多参数 @pytest.mark.parametrize("test_input, expected", [("3+5", 8), ("2+5", 7), ("7+5", 12)])
def test_mark_more(test_input, expected):
assert eval(test_input) == expected
-
用例重命名-添加ids参数 @pytest.mark.parametrize("test_input, expected", [("3+5", 8), ("2+5", 7), ("7+5", 12)], ids=['add_3+5=8', 'add_2+5=7', 'add_3+5=12'])
def test_mark_more(test_input, expected):
assert eval(test_input) == expected
-
笛卡尔积
- 比如:
a=[1,2,3], b=[a,b,c] - 组合:
- (1, a), (1, b), (1, c)
- (2, a), (2, b), (3, c)
- (3, a), (3, b), (3, c)
七、Python代码执行pytest
-
执行:
-
使用main函数 -
使用python -m pytest 调用 pytest(jenkins持续集成用到) if __name__ == "__main__":
pytest.main()
pytest.main(['test_mark1.py::test_dk', '-vs'])
pytest.main(['test_mark1.py', '-vs', '-m', 'dk'])
-
常用的异常处理方法 +try...except try:
可能产生异常的代码块
except [(ERROR1, ERROR2, ...)] [as e]:
处理异常的代码块1
except [(ERROR3, ERROR4, ...)] [as e]:
处理异常的代码块2
except [Exception]:
处理其他异常
-
pytest.raise()
- 可以捕获特定的异常
- 获取捕获的异常的细节(异常类型,异常信息)
- 发生异常,后面的代码将不会被执行
def test_raise():
with pytest.raises(ValueError, match='must be 0 or None'):
raise ValueError("value must be 0 or None")
def test_raise1():
with pytest.raises(ValueError) as exc_info:
raise ValueError("value must be 42")
assert exc_info.type is ValueError
assert exc_info.value.args[0] == "value must be 42"
九、元素定位的常见问题
-
Selenium定位的方法有几种?分别是?
- 有8种定位方法
- 分别是classname、css seletor、id、name、link text、partial link text(当前链接文本)、tagname、xpath
- 最常用的是id、xpath、css seletor、name
-
定位不到元素是什么原因导致的?
-
定位编写错误 -
元素还没有完全加载出来,就去进行定位,导致找不到元素。
- 解决方法:添加隐式等待;
driver.implicitly_wait(5) -
id通常是唯一且不会变化的,但是因为后面前端技术栈的发展,很多id都是动态生成的,且一直再变化
- 解决方法:不使用不稳定的定位方式,比如动态id,而使用更稳定的方式,使用css selector或者xpath定位,比如xpath相对定位:
$x("//*[text()='文本信息']") -
页面有iframe,确认是否有iframe:Ctri+F在Elements页面搜索,找到即代表有,确定要定位的元素是否在iframe里,如果包含,那么就需要切换iframe
- 解决方法:需要切换到对应的iframe之后再进行定位操作:
driver.switch_to.frame(frame) -
存在页面切换
-
元素是隐藏的,如果点击或者操作,那么就会报ElementNotInteractableException ,辨别:Elements页面元素属性包含style="display: none;" 或者 hidden="hidden" 就是元素的隐藏状态
- 解决方法:隐藏按钮不能直接点击,如果要点击,必须使用js进行操作
self.driver.execute_script('document.querySelector(".el-button--info").click()')
-
元素被遮挡
-
selenium中隐藏元素如何定位?
-
如何定位动态元素?
- 解决方法:使用更稳定的方式,比如css selector或者xpath定位,xpath相对定位:
$x("//*[text()='文本信息']") -
如何通过子元素定位父元素? 解决方案:
console里输入表达式:$x("//*[@data-sort-order='default']") 定位到子元素,data-sort-order为属性名,'default’为属性值,然后通过输入表达式:$x("//*[@data-sort-order='default']/..") 定位到父元素 -
如何通过父元素定位子元素? 通过父元素的class定位到父元素,console里输入 $(".class") 回车定位,class为父元素的class属性,然后输入$(".class .sub") 回车定位子元素,sub为子元素的属性值。 -
如何判断一个页面上元素是否存在?
- 通过查看当前页面dom,搜索该元素是否存在,如果是脚本自动化运行过程中,应该通过打印_source,即可了解该元素在运行过程中是否存在
-
有的元素就在加载页面上,但是却定位不到,怎么解决?
-
如果产品总是出现弹窗,导致用例无法执行,应该如何解决?
- 原因:突然出现弹窗,元素被遮挡
- 解决方法:通过添加黑名单异常处理解决
-
一个元素明明定位到了,点击无效(也没报错),如何解决?
- 原因:异步加载js导致点击不到
- 解决方案:利用显示等待循环点击该按钮,直到生效为止
|