说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!
接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/101213973
目录
五丶第四阶段pytest入门
5.Pytest高阶用法(一)
1.pytest之fixture
说明:fixture修饰器来标记固定的工厂函数,在其他函数,模块,类或整个工程调用它时会被激活并优先执行,通常会被用于完成预置处理和重复操作
方法:fixture(scope="function", params=None, autouse=False, ids=None, name=None)
常用参数:
scope:被标记方法的作用域
function" (default):作用于每个测试方法,每个test都运行一次
"class":作用于整个类,每个class的所有test只运行一次
"module":作用于整个模块,每个module的所有test只运行一次
"session:作用于整个session(慎用),每个session只运行一次
params:(list类型)提供参数数据,供调用标记方法的函数使用
autouse:是否自动运行,默认为False不运行,设置为True自动运行
2.fixture第一个例子(通过参数引用)
- 示例代码如下:
- 运行脚本,read_database_data会优先于测试函数运行,通过参数调用函数名并执行pytest的fixture方法,成功执行read_database_data函数里的代码
- 如使用通过参数引用来读写文件中数据,并判断数据,代码如下
- 运行脚本,测试通过
3.fixture第二个例子(通过函数引用)
- 示例代码如下
- 运行结果同理还是成功的,write_file_data会优先于测试类运行
- 在类中再添加一个测试方法,执行测试后,发现运行了两次write_file_data方法以及类中所有的测试方法,换句话说则是有多少个测试方法则会执行多少次write_file_data函数,原因是将装饰器放到了类上面
- 当将装饰器放在测试方法test_01上时,则只会运行一次
4.fixture第三个例子(autouse:是否自动运行,默认为False不运行,设置为True自动运行)
- 示例代码如下
- 运行脚本,before函数自动优先于测试类运行,有几个测试方法,就会执行多少次before,因为scope参数默认为function" (default):作用于每个测试方法,每个test都运行一次
5.fixture第四个例子(设置作用域为function)
- 因为默认scope参数的值就是为function,设置不设置都一样
- 运行脚本,与上一个例子一样
6.fixture第五个例子(设置作用域为class)
- 将scope参数作用域设置为class时,则只运行了一次before函数
- 运行结果如下
7.fixture第六个例子(返回值)
- 示例代码1如下
- 运行脚本结果如下
- 示例代码2如下
- 运行脚本如下,可以发现结果运行了三次,将列表中的所有值都进行了断言
- 示例三 ,在Pytest_Api目录下创建一个名为conftest.py文件,这是一个全局的文件,名称为官方提供的固定名称,编写如下代码
- 在test_api_05.py文件中创建test_b测试方法,通过传递参数的方式来断言全局文件conftest.py文件中的返回值
- 运行脚本,查看结果,成功的获取到全局文件返回值,并进行了断言
6.fixture场景测试
场景描述:首先需要打开设置——定位到位置信息——点击进入位置信息页面(到这里为第一个部分),然后在位置信息页面点击模式——选择准确度高——点击返回按钮即保存——最后断言位置信息页面中模式是否为准确度高(这是第二部分),需要注意的是,第二部分是依赖第一部分,因为第二部分的逻辑为修改模式,第一部分为进入到微信信息页面,那么则需要用到fixture函数引用
- 代码实现如下
- 运行代码成功,在手机端成功修改了模式为准确度高
7.Pytest高阶用法(二)
1.跳过测试函数
根据特定的条件,不执行标识的测试函数.
方法:
skipif(condition, reason=None)
参数:
condition:跳过的条件,必传参数
reason:标注原因,必传参数
使用方法:
@pytest.mark.skipif(condition, reason="xxx")
- 示例代码如下
- 运行代码,test_b函数没有执行
- 运用到场景中跳过某一测试方法,根据函数返回值来进行skipif方法中condition参数的判断条件
- 或者将方法放到类中,也是可以的
- 运行脚本,结果都是一样的跳过test_b测试函数的执行
2.标记为预期失败函数
标记测试函数为失败函数
方法:
xfail(condition=None, reason=None, raises=None, run=True, strict=False)
常用参数:
condition:预期失败的条件,必传参数
reason:失败的原因,必传参数
使用方法:
@pytest.mark.xfail(condition, reason="xx")
- 用法跟跳过测试函数一样,就不用多说了,在代码中将test_b测试函数标记为预期失败函数,则测试结果中会显示1个失败
7.函数数据参数化
方便测试函数对测试属于的获取。
方法:
parametrize(argnames, argvalues, indirect=False, ids=None, scope=None)
常用参数:
argnames:参数名
argvalues:参数对应值,类型必须为list
当参数为一个时格式:[value]
当参数个数大于一个时,格式为:[(param_value1,param_value2.....),(param_value1,param_value2.....)]
使用方法:
@pytest.mark.parametrize(argnames,argvalues)
⚠️ 参数值为N个,测试方法就会运行N次
- 单个参数示例代码如下
- 多个参数示例:
- 函数返回值类型示例:
- 通过return_test_data函数读取data.txt文件数据
8.小结
六丶第五阶段PO模式
1.PO基本介绍
测试PO模式(Page Object Model)
测试页面和测试脚本分离,即页面封装成类,供测试脚本进行调用。
优点:
1.提高测试用例的可读性;
2.减少了代码的重复;
3.提高测试用例的可维护性,特别是针对UI频繁变动的项目;
缺点:
结构复杂: 基于流程做了模块化的拆分。
2.Appium方法二次封装
系统已提供定位方法
driver.find_element_by_id()
driver.find_element_by_class_name()
driver.find_element_by_xpath()
driver.find_elements_by_id()
driver.find_elements_by_class_name()
driver.find_elements_by_xpath()
⚠️ 实际以上定位方法封装以下方法:
find_element(by=By.XX, value=None)
find_elements(by=By.XX, value=None)
# by:定位类型(By.ID,By.CLASS_NAME,By.XPATH)
# value:定位元素的属性值
- 查看方法源码如下所示,最终核心的方法为find_element以及find_elements根据传递的by参数以及value参数的值来进行区分的
- 那么现在只需要封装find_element以及find_elements两个核心方法即可
2.封装实现
- 封装find_element定位元素方法以及click_element点击元素方法,通过类对象调用click_element方法传递元素定位方式以及匹配值
- 运行代码,成功打开设置并点击更多按钮
3.Demo示例
业务场景:
1.进入设置
2.点击搜索按钮
3.输入123
4.点击搜索框返回按钮
- 首先将上一步中的代码中的driver通过参数的方式进行使用,命名为find_element.py文件,并放到base包下
- 然后在test_po_01模块中调用find_element模块方法,完成以上场景(这些封装PO模型博主在web自动化中已经写过了),博主这里将以上场景写成了三个测试方法,为了将控制测试方法执行的顺序,完全可以将以上场景写到一个测试方法中
- 运行测试脚本,成功实现场景
4.显示等待
- 在封装的核心方法find_element进行显示等待操作,设置参数timeout以及poll的固定值
- 运行测试,没有任何问题
5.优化参数
- 需要在我们封装的find_element模块中将调用的原生find_element方法传递的参数进行优化,前面步骤是传递的type元素定位类型以及value元素匹配值,现在则需要将这两个参数使用元组成为一个传递的参数,现在先看一个demo就明白了
- 即在find_element模块中进行如下修改
- 在测试模块中,修改传递的参数,如下
- 运行脚本,测试结果与预期结果一致
3.页面元素操作封装(一)
1.确定好要封装的页面操作
业务场景:
1.进入设置
2.点击搜索按钮
3.输入123
4.点击搜索框返回按钮
2.需要用到哪些元素和定位方法
# 搜索按钮
search_button = (By.ID, "com.android.settings:id/search")
# 搜索输入框
search_text = (By.ID, "android:id/search_src_text")
# 搜索框返回按钮
search_return_button = (By.CLASS_NAME,"android.widget.ImageButton")
3.依赖的定位方法
使用二次封装的方法,find_element.py文件
4.页面封装
- 首先将test_po_01模块放到创建的scripts目录下,然后在模块中将场景中的步骤写到一个测试方法中,因为业务少,所以没有必要写成三个测试方法,博主之所以写成三个是为了方便大家观察了解
- 在page包下创建search_page模块,将test_po_01测试模块中test_001测试方法中的操作元素的代码封装到search_page模块中,如下
- 在scripts目录下创建test_po_02模块,在模块中导入page包下的search_page模块中的Search_Page类,通过实例化Search_Page类,通过这个类的对象来调用上一步封装的search_text方法实现场景
- 运行脚本,成功实现场景
- 使用pytest模块进行参数化
- 运行脚本,成功在设置页面输入框输入列表参数
5.短信业务场景实例
场景描述:打开短信——点击新信息——添加接收人——添加消息——点击发送
- 首先在page包下创建sms_page模块用于封装短信业务场景中的定位元素操作以及业务操作的代码
- 紧接着在scripts测试脚本目录下创建test_po_03测试模块,在模块中通过实例化page包下的sms_page模块中的Sms_Page类,调用以上封装的方法,实现短信场景测试,博主在test_po_03模块中将业务场景分为两个测试方法进行测试,具体如下
- 在运行脚本之前,需要注意修改pytest.ini配置文件中的python_files项的值为test_po_03.py固定值,运行脚本提示以下错误,压根就没有执行test_add_receiver方法而且执行了test_send_message测试方法,导致找不到元素,报错超时异常
- 经过测试发现pytest.fixture装饰器与pytest.mark.run放在一起后就不会执行该测试方法了,所以需要将test_add_receiver方法上的fixture方法修改为mark.parametrize方法进行参数化
- 再次运行测试脚本,成功实现业务场景
6.设置场景优化
- 在第4步中对设置场景进行了简单的封装,现在将设置搜索页面元素定位模块进行拆分,之前在测试模块test_po_02中调用了search_page模块中的search_text方法完成业务场景,现在将该方法拆分成三个方法,如下红框所示
- 在封装的元素操作模块find_element模块中的input_data输入数据方法进行优化,每当调用执行该方法的时候需将输入框内容进行清空操作,避免出现内容不一致
- 创建test_po_04测试模块,通过调用上一步拆分出来的三个方法,来完成搜索页面场景测试
- 运行脚本,肯定是没有问题的
7.通讯录业务场景实现(不难)
场景描述:循环添加三个联系人(打开通讯录——点击添加联系人——点击本地保存——输入姓名丶电话——点击返回按钮(保存)——点击手机返回按钮(返回上一级菜单))
- 首先在page目录下创建telephone_page模块用于封装页面元素,因为在业务场景点击返回按钮这一块定位元素需使用到原生的find_elements方法来获取一组元素以及返回上一级菜单需要使用keyevent方法来向手机发送返回操作,也就是在base目录下的find_element模块中添加针对该业务场景的方法
- 在telephone_page模块中则可以封装定位页面元素操作,如下所示(这些代码都很假单,唯一的需要测试数据来判断是否成功实现场景)
- 在测试模块中完成将业务场景的步骤,分为两个测试方法进行测试(因为要实现以上的场景,就必须这样创建,不然无法循环添加联系人并每次返回)
- 运行脚本,成功实现场景