pytest框架的基本功能使用(一)

前言

pytest是非常成熟、功能强大的测试框架。具有非常多的优点:

  • 简单灵活,容易上手,支持参数化
  • 自动发现测试模块和测试方法
  • 断言使用assert + 表达式即可
  • 可以设置测试会话级、模块级、类级、函数级的fixtures。
  • 共享前置、后置
  • 具有丰富的插件库,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等
  • 用例分标签执行
  • 很好的集成Jenkins
    等等!!!

安装

pytest需要安装:

pip install pytest

安装完成后,验证安装:

pytest --version

在这里插入图片描述

命名规则

刚才在前言中提到,pytest可以自动搜索用例并执行,但是,其实它在搜索用例的时候,有一定的规则:

  • 单测的文件,命名符合test*.py 或者 *_test.py。
  • 以test开头的函数。
  • 以Test开头的测试类(没有__init__函数)当中,以test_开头的函数。
    在这里插入图片描述

标签

  • 标签注册
    在给用例打标签时,首先要注册标签。注册标签的方式有多种,这里只说明第一种:
    首先创建pytest.ini文件,在文件中按如下形式添加标签名:
import pytest

[pytest]
marks=slow:marks tests as slow (delete with '-m "not slow"')
        serial

上面注册了一个标签名为slow的标签。注意:冒号后是【可选的】描述信息,只能用英文,用中文可能会出现一些问题。

当注册完标签名之后,就可以给用例、测试类、测试模块打标签:@pytest.mark.标签名称。
给测试用例打标签,在测试用例函数前:

@pytest.mark.demo
def test_demo3():
    assert 100 == 100

给测试类打标签,写在测试类之前,当给测试类打标签时,类里所有以test开头的函数都拥有此标签,并且还可以再单独给类里的某一个函数打标签,这样,类里的函数即具备类的标签,也有自己的标签:

# @pytest.mark.test
class TestDemo:

    @pytest.mark.demo
    def test_demo(self):
        assert 1001 == 1001

给模块打标签时,在导入的模块之后,所有的用例之前:

import pytest

@pytest.mark.smoke


def test_demo3():
    assert 100 == 100

class TestDemo:

    def test_demo(self):
        assert 1001 == 1001

    def test_demo1(self):
        assert 1 == 1

还可以打多个标签:

@pytest.mark.smoke
@pytest.mark.demo
def test_demo3():
    assert 100 == 100

除了上面的打标签的方式,还有另外一种,比如下面给函数打标签,则写在函数体内:

class TestDemo:

    # 第二种打标签的方式
    pytestmark = pytest.mark.demo
    # 多个标签
    # pytestmark = [pytest.mark.demo, pytest.mark.test]
    def test_demo(self):
        assert 1001 == 1001

    def test_demo1(self):
        assert 1 == 1

当我们给用例、类、模块打上标签之后,就可以根据标签去筛选、运行用例。具体执行方式,在下面运行章节中。

fixture

fixture修饰器来标记固定的工厂函数。在其他函数,模块,类或整个工程调用它时会被激活并优先执行,通常会被用于共享前置、后置,或者其他重复的工作。

测试函数可以直接使用fixture函数的名称作为输入参数,将从fixture函数返回参数传入测试函数。

fixture函数可以使用 return 或 yield 语句将它们的值提供给测试函数。 使用 yield 时,yield在使用时,会起到分割和返回的作用。

在其他模块中,使用fixture时,不需要导入,在运行测试之前调用:可以使用 pytest.mark.usefixtures(fixturename) 标记。

创建conftest.py文件,注意、注意、注意,名称不可修改为其他,只能是conftest.py。
在conftest.py文件中,编写fixture的函数。

fixture方法:

fixture(scope="function", params=None, autouse=False, ids=None, name=None)
  • scope:被标记方法的作用域
    -function (default):作用于每个测试方法,每个test都运行一次
    -class:作用于整个类,类中所有用例之前,执行一次
    -module:作用于整个模块,每个module的所有test只运行一次
    -session:作用于整个session(慎用),每个会话只运行一次
  • params:(list类型)提供参数数据,供调用标记方法的函数使用
  • autouse:是否自动运行,默认为False不运行,设置为True自动运行(一般不要设置为Ture,谨慎开启)

示例:

@pytest.fixture(scope="function")
def init_driver():
    # 前置:打开谷歌浏览器,访问课堂派并登录
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.get(cd.login_url)
    lp = LoginPage(driver)

    # 分割线 +返回值
    # 分割线:当yield前面的代码执行完成之后,执行测试用例,用例执行完,再执行yield之后的代码
    # 返回值:yield之后跟的是返回值,返回的是元组
    yield driver, lp

    # 后置:关闭浏览器
    driver.quit()

当我们在测试中引用时:

@pytest.mark.usefixtures("init_driver")  # 调用函数,init_driver就是我们上面的定义的fixture函数名称
class TestLogin:
    def test_login_success(self,init_driver):  # 传入的init_driver 就是调用init_driver函数返回的值
        init_driver[1].login(ld.normal_datas['user'], ld.normal_datas['passwd'])  # init_driver[1]就是返回的lp,LoginPage的对象
        assert HomePage(init_driver[0]).if_user_is_exist()  # init_driver[0]函数返回的是driver,浏览器对象

fixture函数还可以继承。

  • 同级继承时,比如下面test2继承test1时,都是class级别的,其他模块中调用test2,执行时,会先执行test1的前置,然后执行test2的前置,之后去执行用例,用例执行完成后,去执行test2的后置,然后再执行test1的后置:
@pytest.fixture(scope="class")
def test1():
    # 前置:打开谷歌浏览器,访问**并登录
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.get(cd.login_url)
    lp = LoginPage(driver)

    # 1.分割线 +返回值
    yield driver, lp

    # 后置:关闭浏览器
    driver.quit()

# 继承test1
@pytest.fixture(scope="class")
def test2(test1):
    # 继承test1的前置和后置,作为函数参数,函数名就是返回值
    LoginPage(test1[0]).login(*cd.student_datas)  # 传入test1[0],即test1返回的driver
    yield test1
  • 不同继承作用域比自己大的函数。比如下面的get_home作用域为测试用例,init_course作用域为类,get_home继承init_course,那么在调用get_home时,会先执行login_web的前置,执行一次,每个用例执行完之后,会执行一次get_home后置,所有用例执行完成之后,执行一次login_web的后置:
@pytest.fixture(scope="class")
def login_web(init_course):
    # 前置:打开谷歌浏览器,访问**并登录
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.get(cd.login_url)
    # 以学生账户登录
    LoginPage(driver).login(*cd.student_datas)
    cp = CoursePage(driver)
    yield driver, cp
    driver.quit()

# 继承类的前置,执行时,会执行类的前置,然后每一个用例会执行get_home的后置
@pytest.fixture(scope="function")
def get_home(login_web):
    yield login_web
    login_web[0].get(cd.login_url)

运行

cmd命令运行:
在这里插入图片描述
使用cmd命令运行时,要注意cmd的目录,因为不指定目录时,默认在那个路径下,就去那个路径下寻找用例。

pycharm中terminal中通过命令运行:
在这里插入图片描述
这个其实和在cmd命令中一样。

执行指定标记的用例:

pytest -m smoke  # 执行标记为smoke的用例

指定测试模块:

pytest test_001.py  # 测试test_001.py文件中的用例

指定测试目录:

pytest testcases/  # 测试testcases目录下的用例

关键字筛选执行:

pytest -k "TestClass and not method"

这条命令会匹配文件名、类名、方法名匹配表达式的用例,这里这条命令会运行 TestClass.test_smoke, 不会执行 TestClass.test_method_smoke

运行指定测试用例:

pytest test_001.py::test_add  #执行test_001.py文件中的test_add函数

除了使用命令运行,还可以使用main函数运行:

import pytest


if __name__ == '__main__':
    pytest.main()  # 和命令行运行的形式一样

和命令行的运行是一样的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值