美文网首页
pytest学习

pytest学习

作者: 安明_555 | 来源:发表于2019-07-24 14:25 被阅读0次

使用环境准备

  • python==3.6.7
  • pycharm
  • pytest 5.0.1
pytest用例规范
  • 测试文件以test_开头(已_test结尾)
  • 测试类以Test开头,并且不能带有init方法
  • 测试函数以test_开头
  • 断言使用 assert
使用pycharm编辑器,设置pytest框架 >> File >> settings >> Tools >> Python Integrated Tools >> Default test runner : pytest pycharm中pytest框架设置
快速开始
  1. 新建一个test_demo.py文件,写入以下代码
# test_demo.py

def test_one():
    assert 1 == 2
def test_two():
    assert 2 == 2
  1. 使用pycharm编辑器执行,它会自动识别是否使用了pytest框架


    test_demo.py 执行结果
写一个测试类
  1. 当用例越来越多的时候,使用函数就不合适了,可以写到一个类里面
# test_class.py

class TestClass:
    def test_one(self):
        assert 1 == 2
    def test_two(self):
        assert 2 == 2

2.更改控制用例顺序

# test_class.py

import pytest

class TestClass:

    def test_one(self):
        assert 1 == 2

    @pytest.mark.run(order=1)  # 使用pytest.mark.run() 函数控制用例执行顺序
    def test_two(self):
        assert 2 == 2
未使用pytest.mark.run() 使用pytest.mark.run()
用例运行级别

setup_module
setup_class
setup_method
teardown_method
teardown_class

teardown_module

  • setup_class/teardown_class需配合@classmethod使用
# test_pytest_object.py

import logging
import pytest

logging.basicConfig(level=logging.DEBUG)

def setup_module():
    logging.info("setup_module:整个.py模块下,只执行一次")
def teardown_module():
    logging.info("teardown_module:整个.py模块下,只执行一次")

class TestPytestObject2:
    def test_three(self):
        assert [1, 2] == [1, 3]
    def test_foure(self):
        assert {"a": 1, "b": "sss"} == {"a": 2, "b": "ss"}

class TestPytestObject:

    @classmethod
    def setup_class(cls):
        logging.info("setup_class:该class下,所有用例前面执行一次")

    def setup_method(self):
        logging.info("setup_methon:每个用例开始前都会执行")

    def test_two(self):
        assert 1 == 2
    def test_one(self):
        assert 2 == 2

    def teardown_method(self):
        logging.info("teardown_method:每个用例结束后都会执行")

    @classmethod
    def teardown_class(cls):
        logging.info("teardown_class:该class下,所有用例后面执行一次")
pytest参数化
  1. 使用 @pytest.mark.paramtrize() 装饰器传参
# clac.py

class Clac:
    def add(self, a, b):
        return a + b

    def div(self, a, b):
        return  a/b

对Clac()方法进行参数化测试

# test_pytest_param.py

import pytest
from src.clac import Clac

class TestClac:
    clac = Clac()

    @pytest.mark.parametrize("a, b, c", [
        (1, 2, 3),
        (-1, 3, 2),
        (10000, 9999, 19999),
        (-1, 0, -1)
    ])
    def test_add(self, a, b, c):
        assert self.clac.add(a, b) == c
  1. 读取json文件传参
# test_pytest_param.py

import pytest
import json
from src.clac import Clac

class TestClac:
    clac = Clac()

    '''把读取json文件获得的数据,通过参数传递'''
    @pytest.mark.parametrize("a, b, c",  json.load(open("clac.json")))
    def test_div(self, a, b, c):
        assert self.clac.div(a, b) == c
  1. 读取yaml文件,进行数据驱动,实现参数化
  • pytest框架使用yaml,很少用json,因为json格式比较严格,不支持注释;所以,我们用yaml
  • 先创建一个clac.yaml文件,详细的yaml格式可以参考这个文档
# test_pytest_param.py

import pytest
import yaml
from src.clac import Clac

class TestClac:
    clac = Clac()

    '''把读取yaml文件获得的数据,通过参数传递'''
    @pytest.mark.parametrize("a, b, c",  yaml.load(open("clac.yaml")))
    def test_div(self, a, b, c):
        assert self.clac.div(a, b) == c
pytest fixture的使用

像上面讲到的setup和teardown可以实现在测试用例运行前后加入一些操作,但这种是整个脚本全局生效的。如果我想实现这样的场景:用例1登录,用例2不需要登录,用例3需要先登录,这样的话setup/teardown是不能满足的,这就是学习fixture的目的,自定义测试用例的预置条件

fixture的作用
  • 完成setup和teardown操作,处理数据库、文件等资源的打开和关闭
  • 完成大部分测试用例需要完成的通用操作,例如login、设置config参数、环境变量等
  • 准备测试数据,将数据提前写入到数据库,或者通过params返回给test用例,等
fieture的优势
  • 命名方式灵活,不局限于setup和teardown这几个命名
  • conftest.py 配置里可以实现数据共享,不需要import就能自动找到一些配置
  • scope="module" 可以实现多个.py跨文件共享前置, 每一个.py文件调用一次
  • scope="session" 以实现多个.py跨文件使用一个session来完成多个用例
fixture(scope="function", params=None, autouse=False, ids=None, name=None):
    '''使用装饰器标记fixture的功能
     可以使用此装饰器(带或不带参数)来定义fixture功能。 fixture功能的名称可以在以后使用
     引用它会在运行测试之前调用它:test模块或类可以使用pytest.mark.usefixtures(fixturename标记。 
     测试功能可以直接使用fixture名称作为输入参数,在这种情况下,夹具实例从fixture返回功能将被注入。'

    :arg scope: scope 有四个级别参数 "function" (默认), "class", "module" or "session".

    :arg params: 一个可选的参数列表,它将导致多个参数调用fixture功能和所有测试使用它

    :arg autouse:  如果为True,则为所有测试激活fixture func 可以看到它。 如果为False(默认值)则显式需要参考来激活fixture

    :arg ids: 每个字符串id的列表,每个字符串对应于params 这样他们就是测试ID的一部分。 如果没有提供ID它们将从params自动生成

    :arg name:   fixture的名称。 这默认为装饰函数的名称。 如果fixture在定义它的同一模块中使用,夹具的功能名称将被请求夹具的功能arg遮蔽; 解决这个问题的一种方法是将装饰函数命名
                       “fixture_ <fixturename>”然后使用”@ pytest.fixture(name ='<fixturename>')“”。

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

# -*- coding=utf-8 -*-
# 新建一个test_demo.py
import pytest

"不带参数时,默认scope=function"
@pytest.fixture()
def topics():
    print("\n输入账号、密码,先登录")

def test_1(topics):
    print("用例1:登录后,进行操作111\n")

def test_2():
    print("用例2:无需登录")

def test_3(topics):
    print("用例3:登录之后,执行其他动作222")
function级别执行结果

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

# -*- coding=utf-8 -*-
# 新建一个test_demo.py
import pytest

@pytest.fixture(scope="module")
def topics():
    print("\n输入账号、密码,先登录")

def test_1(topics):
    print("用例1:登录后,进行操作111\n")

def test_2(topics):
    print("用例2:无需登录\n")

def test_3(topics):
    print("用例3:登录之后,执行其他动作222")
module级别执行结果

从结果看出,module级别的fixture在当前.py模块里,只会在用例(test_1)第一次调用前执行一次

3. 定义一个session级别的fixture

  • 先创建一个conftest.py文件,输入一下代码
    conftest.py 配置里可以实现数据共享,当有测试用例使用pytes.fixture函数时,pytest会自动去配置文件里寻找pytest.fixture,不需要import就能自动找到一些配置
import pytest

@pytest.fixture(scope="session")
def topics():
    print("\n 输入账号、密码,先登录")

创建test_fixture.py,输入一下代码

# 新建一个test_fixture.py

def test_1(topics):
    print(" 用例1:登录后,进行操作111")

def test_2(topics):
    print("用例2:无需登录")

创建test_fixture2.py,输入一下代码

# 新建一个test_fixture2.py

def test_3(topics):
    print("\n 用例3:登录后,进行操作111")

def test_4(topics):
    print("用例4:无需登录")

在Terminal窗口下,执行以下命令

(venv) F:\CAM\Appiumdemo\case>pytest -s F:\CAM\Appiumdemo\case\test_fixture.py F:\CAM\Appiumdemo\case\test_fixture2.py
session级别执行结果

从结果可以看出,session级别的fixture,在两个模块时,只会在所有用例前执行一次

yield生成器执行teardown

前面的在用例前预置条件,相当setup,在fixture里使用yield来执行teardown

相关文章

网友评论

      本文标题:pytest学习

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