预习笔记02-pytest测试框架

  • Pytest
    1)结合 Requests 实现接口测试
    2)结合 Selenium / Appium 实现Web / APP自动化功能测试
    3)结合Allure集成到Jenkins中实现持续集成
    选择pytest的原因
    ①报告(Allure);②多线程(distributed testing plugin);③控制顺序(pytest-ordering插件);④兼容unittest;⑤定制化插件开发。

  • Pytest 环境安装
    方式一:命令 pip install -U pytest
    方式二:在Pycharm的 Settings-Project Interpreter 中直接安装

  • Pytest 格式要求
    1)文件:test_开头 或者 _test 结尾
    2)类:Test 开头
    3)方法/函数:test_开头
    4)注意:测试类中不可以添加__init__构造函数

    • 函数(function):在类外部 / 方法(method):在类内部。

Python风格规范 — Google 开源项目风格指南

  • Pytest 测试框架结构
    setup_module/teardown_module 全局模块级
    setup_class/teardown_class 类级,只在类中前后运行一次(常用)
    setup_function/teardown_function 函数级,在类外
    setup_method/teardown_methond 方法级,类中的每个方法执行前后(用法同下)
    setup/teardown 在类中,运行在调用方法的前后(重点)

  • 运行结果分析
    常见结果:fail / error / pass
    特殊结果:warning / deselected

  • 运行测试用例

方式一:使用pytest解释器,打开terminal 或 cmd,cd到项目路径
1)执行包下所有用例:pytest
2)执行单独一个pytest模块:pytest 文件名.py
3)执行某个模块中某个类:pytest 文件名.py::类名
4)执行某个模块中某个类里面的方法:pytest 文件名.py::类名::方法名

方式二:使用python解释器,执行pytest.main函数

#入口
if __name__ == '__main__':
    #1、运行当前目录下所有符合规则的用例,包括子目录(test_*.py 和 *_test.py)
    pytest.main()
    #2、运行某个模块中的某一条用例
    pytest.main(['test_mark.py::test_case2', '-vs'])
    #3、运行某个标签
    pytest.main(['test_search.py', '-vs', '-m', 'str'])

运行方式
python test_*.py #入口函数所在的文件


使用 python -m pytest test_*.py 调用pytest(jenkins持续集成用到)

  • 常用命令行参数
    –help
    -v 打印详细日志
    -s 打印输出日志(一般-vs)
    -x 用例一旦失败(fail/error),立刻停止执行
    --maxfail=num 用例失败数达到,则不再继续执行
    -k “xx” 执行包含某个关键字的测试用例
    --collect-only (测试平台,pytest 自动导入功能 )
    --lf(--last-failed) 只重新运行故障
    --ff(--failed-first) 先运行故障然后再运行其余的用例

  • 使用Mark标记测试用例
    场景:可以把一个web项目划分成多个部分,根据标签名指定用例去执行。
    语法:在测试用例方法上加 @pytest.mark.标签名(英文)
    举例:加 -m 参数执行
    pytest -s test_mark_zi_09.py -m=webtest
    pytest -s test_mark_zi_09.py -m apptest
    pytest -s test_mark_zi_09.py -m "not ios"

    • 不提示warning:创建pytest.ini文件,将所有标签名列举出来
[pytest]

markers = str
        min
        ios
  • Mark:跳过(skip) 预期失败(xFail)

skip用法1:添加装饰器 @pytest.mark.skip * @pytest.mark.skipif
skip用法2:在代码中跳过 pytest.skip(reason)


@pytest.mark.skip(reason="跳过本条")
def test_mark_func():
    print("test mark function")

print(sys.platform)
@pytest.mark.skipif(sys.platform == "darwin", reason="does not run on mac")
def test_case1():
    assert True
@pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows")
def test_case2():
    assert True
@pytest.mark.skipif(sys.version_info < (3,  6), reason="requires python3.6 or higher")
def test_case3():
    assert True

def login():
    return False
def test_func():
    print("111")
    if not login():
        pytest.skip("unsupported function")#条件符合,执行跳过,后面的代码不再执行
    print("end")

xfaile用法1:@pytest.mark.xfail #提示用例失败的作用,用法类似于skip
xfaile用法2:在代码中跳过 pytest.xfail(reason)

  • Mark参数化–将模型中的定量信息变量化

1、单参数

search_list = ['appium', 'selenium', 'pytest']
@pytest.mark.parametrize('name', search_list)
def test_search(name):
    assert name in search_list

2、多参数
3、用例重命名(ids)

#1、参数化的名字,要与方法中传入的参数名,一一对应
#2、如果传递多个参数,要放在列表中,列表中嵌套列表/元组
#3、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

4、笛卡尔积(全量:全组合)

  • 常用的异常处理方法

1、try…except

try:
    a = int(input("输入被除数:"))
    b = int(input("输入除数:"))
    c = a / b
    print("您输入的两数相除的结果是:", c)
except (ValueError, ArithmeticError):
    print("程序发生了 数字格式异常、算数异常 之一")
except :
    print("未知异常")
print("程序继续运行")

2、pytest.raises()

def test_raise():
    with pytest.raises(ValueError, ZeroDivisionError):#异常为当中的一个,则抛出
        raise ZeroDivisionError("除数为0")

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"
2 个赞

整理的很不错 :+1:

当有多个异常时,异常应传入元组类型,代码应为

def test_raise():
    with pytest.raises((ValueError, ZeroDivisionError)):#异常为当中的一个,则抛出
        raise ZeroDivisionError("除数为0")

运行了一下,确实报错了。多个异常需要以元组传入
多谢指正~