pytest测试框架

作者: 相忘于江湖eyu | 来源:发表于2020-01-12 08:07 被阅读0次

介绍

是什么

python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高

安装

pip install -U pytest

举例

测试文件

# content of test_sample.py
 
def func(x):
    return x+1
 
def test_func():
    assert func(3) == 3

运行测试

$ py.test
=========================== test session starts ============================
platform linux -- Python 3.4.1 -- py-1.4.27 -- pytest-2.7.1
rootdir: /tmp/doc-exec-101, inifile:
collected 1 items
test_sample.py F
================================= FAILURES =================================
_______________________________ test_answer ________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:5: AssertionError
========================= 1 failed in 0.01 seconds =========================         

使用

编写规则

编写pytest测试样例非常简单,只需要按照下面的规则:

  • 测试文件以test_开头(以_test结尾也可以)
  • 测试类以Test开头,并且不能带有 init 方法
  • 测试函数以test_开头
  • 断言使用基本的assert即可

执行测试

py.test               # run all tests below current dir
py.test test_mod.py   # run tests in module
py.test somepath      # run all tests below somepath
py.test -k stringexpr # only run tests with names that match the
                      # the "string expression", e.g. "MyClass and not method"
                      # will select TestMyClass.test_something
                      # but not TestMyClass.test_method_simple
py.test test_mod.py::test_func # only run tests that match the "node ID",
                   # e.g "test_mod.py::test_func" will select
                               # only test_func in test_mod.py

测试报告

安装pytest-html插件

pip install pytest-html

执行生成

py.test --html=path

生成xml报告(无需插件)

py.test --junitxml=path

覆盖率

安装插件pytest-cov

pip install pytest-cov

执行

pytest --cov-report=html --cov=./ test_code_target_dir

注:这里的覆盖率值被测试函数的覆盖率,未被显式测试函数不参与覆盖率计算

参数说明

  • --cov=[path], measure coverage for filesystem path (multi-allowed), 指定被测试对象,用于计算测试覆盖率
  • --cov-report=type, type of report to generate: term, term-missing, annotate, html, xml (multi-allowed), 测试报告的类型
  • --cov-config=path, config file for coverage, default: .coveragerc, coverage配置文件
  • --no-cov-on-fail, do not report coverage if test run fails, default: False,如果测试失败,不生成测试报告
  • --cov-fail-under=MIN, Fail if the total coverage is less than MIN. 如果测试覆盖率低于MIN,则认为失败

获取帮助

py.test --version # shows where pytest was imported from
py.test --fixtures # show available builtin function arguments
py.test -h | --help # show help on command line and config file options
  • -v 用于显示每个测试函数的执行结果
  • -q 只显示整体测试结果
  • -s 用于显示测试函数中print()函数输出
  • -x, --exitfirst, exit instantly on first error or failed test
  • -h 帮助

其他功能

  • 测试顺序随机
pip install pytest-randomly
  • 分布式测试
pip install pytest-xdist
  • 出错立即返回
pip install pytest-instafail

fixture

fixture是pytest的精髓所在,就像unittest中的setup和teardown一样

fixture用途

1.做测试前后的初始化设置,如测试数据准备,链接数据库,打开浏览器等这些操作都可以使用fixture来实现
2.测试用例的前置条件可以使用fixture实现
3.支持经典的xunit fixture ,像unittest使用的setup和teardown
4.fixture可以实现unittest不能实现的功能,比如unittest中的测试用例和测试用例之间是无法传递参数和数据的,但是fixture却可以解决这个问题

fixture定义

fixture通过@pytest.fixture()装饰器装饰一个函数,那么这个函数就是一个fixture

# test_fixture.py

import pytest

@pytest.fixture()
def fixtureFunc():
    return 'fixtureFunc'

def test_fixture(fixtureFunc):
    print('我调用了{}'.format(fixtureFunc))

if __name__=='__main__':
    pytest.main(['-v', 'test_fixture.py'])

fixture三种使用方式

  • Fixture名字作为用例的参数
    同上面例子
  • 使用@pytest.mark.usefixtures('fixture')装饰器
# test_fixture.py
import pytest
@pytest.fixture()
def fixtureFunc():
    print('\n fixture->fixtureFunc')

@pytest.mark.usefixtures('fixtureFunc')
def test_fixture():
    print('in test_fixture')

@pytest.mark.usefixtures('fixtureFunc')
class TestFixture(object):
    def test_fixture_class(self):
        print('in class with text_fixture_class')

if __name__=='__main__':
    pytest.main(['-v', 'test_fixture.py'])
  • 使用autouse参数(慎用)
    指定fixture的参数autouse=True这样每个测试用例会自动调用fixture
# test_fixture.py
import pytest
@pytest.fixture(autouse=True)
def fixtureFunc():
    print('\n fixture->fixtureFunc')

def test_fixture():
    print('in test_fixture')

class TestFixture(object):
    def test_fixture_class(self):
        print('in class with text_fixture_class')

if __name__=='__main__':
    pytest.main(['-v', 'test_fixture.py'])

三种方式的区别:
如果测试用例需要使用fixture中返回的参数,那么通过后面这两种方式是无法使用返回的参数的,因为fixture中返回的数据默认存在fixture名字里面存储,所以只能使用第一种方式才可以调用fixture中的返回值。

fixtur作用范围

scope参数可以是session, module,class,function; 默认为function
1.session 会话级别(通常这个级别会结合conftest.py文件使用,所以后面说到conftest.py文件的时候再说)
2.module 模块级别: 模块里所有的用例执行前执行一次module级别的fixture
3.class 类级别 :每个类执行前都会执行一次class级别的fixture
4.function :前面实例已经说了,这个默认是默认的模式,函数级别的,每个测试用例执行前都会执行一次function级别的fixture

# test_fixture.py
import pytest

@pytest.fixture(scope='module', autouse=True)
def module_fixture():
    print('\n-----------------')
    print('我是module fixture')
    print('-----------------')
@pytest.fixture(scope='class')
def class_fixture():
    print('\n-----------------')
    print('我是class fixture')
    print('-------------------')
@pytest.fixture(scope='function', autouse=True)
def func_fixture():
    print('\n-----------------')
    print('我是function fixture')
    print('-------------------')

def test_1():
    print('\n 我是test1')

@pytest.mark.usefixtures('class_fixture')
class TestFixture1(object):
    def test_2(self):
        print('\n我是class1里面的test2')
    def test_3(self):
        print('\n我是class1里面的test3')
@pytest.mark.usefixtures('class_fixture')
class TestFixture2(object):
    def test_4(self):
        print('\n我是class2里面的test4')
    def test_5(self):
        print('\n我是class2里面的test5')

if __name__=='__main__':
    pytest.main(['-v', '--setup-show', 'test_fixture.py'])

fixture实现teardown

其实前面的所有实例都只是做了测试用例执行之前的准备工作,那么用例执行之后该如何实现环境的清理工作呢?答案是使用yield关键字

import pytest
from selenium import webdriver
import time
@pytest.fixture()
def fixtureFunc():
  '''实现浏览器的打开和关闭'''
    driver = webdriver.Firefox()
    yield driver
    driver.quit()
def test_search(fixtureFunc):
    '''访问百度首页,搜索pytest字符串是否在页面源码中'''
    driver = fixtureFunc
    driver.get('http://www.baidu.com')
    driver.find_element_by_id('kw').send_keys('pytest')
    driver.find_element_by_id('su').click()
    time.sleep(3)
    source = driver.page_source
    assert 'pytest' in source
    
if __name__=='__main__':
    pytest.main(['--setup-show', 'test_fixture.py'])

参考文档

python测试框架
pytest文档
主流测试框架1
主流测试框架2

相关文章

网友评论

    本文标题:pytest测试框架

    本文链接:https://www.haomeiwen.com/subject/ishuactx.html