pytest学习笔记

2019-07-19  本文已影响0人  test小星星

使用环境


pytest编写规范

实例

  1. 设置pycharm为pytest运行


    pytest
  2. 创建demo.py文件
# 加法
def add(a, b)
  return a + b
  1. 创建test_demo.py 文件
from src.demo import add
 
# 测试加法
def test_add():
    assert add(1, 2) == 3
    assert add(1, 0) == 1
    assert add(1, -1) == 0
  1. 使用pycharm执行test_demo文件
  2. 使用命令行执行pytest test_demo

常用的pytest第三方插件

插件安装方式pip install 插件名称

def test_add():
    assert add(1, 2) == 3
    assert add(1, 0) == 2
    assert add(1, -1) == 0

执行结果

执行结果 可以看出assert add(1, -1) == 0的测试用例并没有被执行。
使用pytest-assume
def test_add(self):
  pytest.assume(add(1, 2) == 3)
  pytest.assume(add(1, 0) == 2)
  pytest.assume(add(1, -1) == 0)
import pytest
class TestAdd():

    @pytest.mark.run(order=2)
    def test_add1(self):
        print('test_add1')
        pytest.assume(add(1, 2) == 3)

    @pytest.mark.run(order=1)
    def test_add2(self):
        print('test_add2')
        pytest.assume(add(1, -1) == 0)

# order=1先执行,order=2后执行
# pytest-rerunfailures执行方式
pytest --reruns 3 test_demo.py  # 3代表失败后重新运行的次数,如果加上正常运行的次数总共是4次

pytest参数化

通过@pytest.mark.parametrize装饰器传参

import pytest
# 加法
def add(a, b):
    return a + b

# 参数
@pytest.mark.parametrize(
  'a, b, re', [
        (3, 4, 7),
        (1, -1, 0),
        (1, 1.2, 2.2),
])
# 测试加法
def test_add(a, b, re):
    pytest.assume(add(a, b) == re)

通过读取文件的形式参数化
读json文件

import json
import pytest

# 读取json文件
def load_json():
    with open('test.json', 'r') as f:
        re = json.load(f)
    return re

# 加法运算
def add(a, b):
    return a + b

# 把读到文件的数据通过参数传递
@pytest.mark.parametrize('a, b, re', load_json())
# 测试加法运算
def test_add(a, b, re):
    pytest.assume(add(a, b) == re)

读yaml文件

import yaml
import pytest

# 读取yaml文件
def load_json():
    with open('test.yaml', 'r') as f:
        re = yaml.load(f)
    return re

# 加法运算
def add(a, b):
    return a + b

# 把读到文件的数据通过参数传递
@pytest.mark.parametrize('a, b, re', load_json())
# 测试加法运算
def test_add(a, b, re):
    pytest.assume(add(a, b) == re)

说明: pytest.mark.parametrize的第一个参数代表测试方法接收的参数个数,第二个参数为接收的数据内容。如果是通过读文件的形式传参需要注意读出来的文件内容是否和要传的参数类型一致。


pytest执行级别

  1. setup_module 模块级别

如果在单个模块中有多个测试函数和测试类,则可以选择实现以下方法(只会执行一次)

def setup_module():
""" 模块执行前准备工作 """

class Test1():
  """ 测试类1 """
class Test2():
  """ 测试类2 """

def teardown_module():
    """ 模块执行后的结束工作 """
  1. setup_class 类级别

在调用类的所有测试方法之前和之后调用以下方法(只会执行一次)

class TestDemo():
  @classmethod
  def setup_class(cls):
      """ 类方法执行前准备工作 """
  
  def test_add(self):
    "" 测试方法 """
  
  @classmethod
  def teardown_class(cls):
    """ 类方法执行后结束工作 """
  1. setup_method 方法级别

围绕每个方法执行之前之后调用以下方法(每个方法执行之前都会执行一次)

class Test1():
  def setup_method(self):
    """ 每个方法执行之前准备工作  """

  def test_add1(self):
    """ 测试方法1 """  
  
    def test_add2(self):
    """ 测试方法1 """ 
 
  def teardown_method(self):
    """ 每个方法执行之后结束工作 """
  1. setup_function 函数级别

在执行每个函数执行,调用以下方法(只会执行一次)

def setup_function():
    """ 函数执行前准备工作 """

def test_add1():
  """ 测试函数1 """ 

def test_add2():
  """ 测试函数2 """ 

def teardown_function():
    """ 函数执行后结束工 """

pytest fixtures

fixture函数的作用:

fixture 参数
scope参数
scope=function:每个test都运行,默认是function的scope
scope=class:每个class的所有test只运行一次
scope=module:每个module的所有test只运行一次
scope=session:每个session只运行一次

1. 定义一个函数级别的fixture

import pytest

# 定义fixture函数
@pytest.fixture()
def fixture_func():
    print("\n这是一个fixture函数,用来完成一些提前准备")

def test_1(fixture_func):
    print('测试用例1')
    assert 1==1
def test_2(fixture_func):
    print('测试用例2')
    assert 2==2

函数级别的fixture执行结果


函数级别执行结果

2. 定义一个模块级别的fixture

@pytest.fixture(scope="module")
def fixture_func():
    print("\n这是一个fixture函数,用来完成一些提前准备")

def test_1(fixture_func):
    print('测试用例1')
    assert 1==1

def test_2(fixture_func):
    print('测试用例2')
    assert 2 == 2

模块级别的fixture执行结果


module级别执行结果

3. 定义一个session级别fixture
(1) 先创建一个conftest.py文件,输入以下代码
说明:当有测试用例调用pytest.fixture函数时,pytest会自动去找conftest.py文件里找pytest.fixture函数,不需要import。

import pytest

@pytest.fixture(scope="session")
def fixture_func():
   print("\n这是一个fixture函数,用来完成一些提前准备")

(2) 创建第一个测试用例文件 test_demo.py

def test_1(fixture_func):
    print('测试用例1')
    assert 1 == 1

def test_2(fixture_func):
    print('测试用例2')
    assert 2 == 2

(3) 创建第二个测试用例文件 test_demo2.py

def test_1(fixture_func):
    print('测试用例3')
    assert 3 == 3

def test_2(fixture_func):
    print('测试用例4')
    assert 4 == 4

(4) 使用命令行执行测试用例

$ pytest -s test_*

(5) session级别fixture执行结果


session级别执行结果

4. 加上yield的fixture函数
以上几个级别都是相当于steup的方法,加上yield可以构造出相当于teardown的方法。如下

import pytest

def start_prepare():
    print("\n这是一个用来执行测试之前的准备工作")

def end_operation():
    print("\n这是一个用来执行测试结束时的结束工作")

# fixture函数
@pytest.fixture(scope="module")
def fixture_func():
    print("测试开始")
    # 当程序碰到yield会先执行yield前面的代码,等代码都执行完后回到yield处继续执行后面的代码
    yield start_prepare() 
    end_operation()
 

# 测试用例
def test_1(fixture_func):
    print('测试用例1')
    assert 1==1

def test_2(fixture_func):
    print('测试用例2')
    assert 2 == 2

yield 执行结果


yield执行结果

下面来看下函数级别的fixture函数加上yield后的结果

import pytest

def start_prepare():
    print("\n这是一个用来执行测试之前的准备工作")

def end_operation():
    print("\n这是一个用来执行测试结束时的结束工作")

@pytest.fixture()
def fixture_func():
    print("测试开始")
    yield start_prepare()
    end_operation()


# 测试用例
def test_1(fixture_func):
    print('测试用例1')
    assert 1==1

def test_2(fixture_func):
    print('测试用例2')
    assert 2 == 2

yield 执行结果


执行结果

说明:
当测试用例调用了fixture_func函数会先执行fixture_func函数的代码
执行顺序是:

  1. print("测试开始")
  2. start_prepare()
  3. print('测试用例1')
  4. assert 1==1
  5. yield
  6. end_operation()

5. 使用addfinalizer()方法实现类似teardown的方法

import pytest

def start_prepare():
    print("\n这是一个用来执行测试之前的准备工作")

@pytest.fixture()
def fixture_func(request):  # 注意需要加个request参数
    print("\n测试开始")

    def end_operation():
        print("\n这是一个用来执行测试结束时的结束工作")
    # 主要是这句代码来完成结束工作
    request.addfinalizer(end_operation)
    return start_operation()

# 测试用例
def test_1(fixture_func):
    print('测试用例1')
    assert 1==1

def test_2(fixture_func):
    print('测试用例2')
    assert 2 == 2

addfinalizer()方法执行结果


addfinalizer()执行结果

6. fixture参数化

import pytest

@pytest.fixture(params=[
    "参数1",
    "参数2"
])
def fixture_func(request):
    str = request.param
    print(f"\n{str}")


# 测试用例
def test_1(fixture_func):
    print('测试用例1')
    assert 1==1

执行结果,可以看出一个用例执行了两次

参数化执行结果

调用fixture的三种方式
方式1: 在测试用例中直接调用它,把fixture函数当做参数传入,例如上面的例子。

方式2:使用@pytest.mark.usefixtures("fixture函数名称")装饰器

import pytest


@pytest.fixture()
def fixture_func():
    print("\n测试前准备")


@pytest.mark.usefixtures("fixture_func")
def test_1():
    print("函数测试用例1")
    assert 1 == 1


@pytest.mark.usefixtures("fixture_func")
def test_2():
    print('函数测试用例2')
    assert 1 == 1


class Test1:
    @pytest.mark.usefixtures("fixture_func")
    def test_3(self):
        print('类测试用例1')
        assert 1 == 1

    @pytest.mark.usefixtures("fixture_func")
    def test_4(self):
        print('类测试用例2')
        assert 1 == 1


@pytest.mark.usefixtures("fixture_func")
class Test2:
    def test_5(self):
        print('类测试用例3')
        assert 1 == 1

    def test_6(self):
        print('类测试用例4')
        assert 1 == 1

执行结果


@pytest.mark.usefixtures()执行结果

方式3: 用autos调用fixture,autouse 默认设置为False。 当默认为False,就可以选择用上面两种方式来试用fixture。 当设置为True时,在一个session内的所有的test都会自动调用这个fixture,所以用该功能时要谨慎小心。
@pytest.fixture(scope="function", autouse=True)

import pytest


@pytest.fixture(scope="function", autouse=True)
def fixture_func():
    print("\n测试前准备")


def test_1():
    print("函数测试用例1")
    assert 1 == 1


def test_2():
    print('函数测试用例2')
    assert 1 == 1


class Test1:

    def test_3(self):
        print('类测试用例1')
        assert 1 == 1

    def test_4(self):
        print('类测试用例2')
        assert 1 == 1


class Test2:
    def test_5(self):
        print('类测试用例3')
        assert 1 == 1

    def test_6(self):
        print('类测试用例4')
        assert 1 == 1

执行结果


autouse=True执行结果
上一篇下一篇

猜你喜欢

热点阅读