pytest

pytest是python语言中一款强大的单元测试框架,用来管理和组织测试用例,可应用在单元测试、自动化测试工作中。

unittest也是python语言中一款单元测试框架,但是功能有限,没有pytest灵活。
pytest和unittes就是好用和更好用的对比。所以准备学习unittest的伙伴可以放弃入坑了哈哈哈,纯属调侃pytest是基于unittest封装的,学好unittest就会更好的理解pytest。
1、pytest的安装,怎么装

2、pytest的特征、与unittest的区别

3、pytest如何自动识别用例

4、pytest框架中,用例的运行顺序

5、pytest的简单示例,怎么用

一.pytest 怎么安装
pip install pytest

二.pytest的特征、与unittest的区别

pytest的特征如下:

◆ 自动识别测试用例(unittest当中,需要引入TestSuite,主动加载测试用例。)

◆ 简单的断言表达:assert 表达式即可(unittest当中,self.assert*)

◆ 有测试会话、测试模块、测试类、测试函数级别的fixture(unittest当中是测试类、测试函数级别的fixture)

◆ 有非常丰富的插件,目前在600+,比如allure插件(unittest无)

◆ 测试用例不需要封装在测试类当中(unittest中需要自定义类并继承TestCase)

  • case的py文件名必须是test开头
    def用例必须是test开头
    class名必须是Test开头,注意大写
    class中的def用例必须是test开头

那么pytest是如何自动识别测试用例的呢?我们在编写pytest用例的时候,需要遵守哪些规则呢?


三.pytest如何自动识别用例
识别规则如下:
一.搜索根目录:默认从当前目录中搜集测试用例,即在哪个目录下运行pytest命令,则从哪个目录当中搜索;
二.搜索规则:
1.搜索文件:符合命名规则 test_*.py 或者 *_test.py 的文件
2.在满足1)的文件中识别用例的规则:
以test_开头的函数名;
以Test开头的测试类(没有init函数)当中,以test_开头的函数
四.pytest框架中,用例的运行顺序

原则:先搜索到的py文件中的用例,先执行。在同一py文件当中,按照代码顺序,先搜索到的用例先执行。 

五.pytest的简单示例,怎么用

在pytest中,它会首先寻找以test_开头或者以_test结尾的测试模块,然后执行模块里面

以test_开头或者是以_test结尾的测试代码,这里依据这个要去,编写测试模块,如下:

import random

def test_demo1():
    """
    pytest  简单示例1
    """
    assert 5 ==random.randint(1,10)

运行结果:

其实这就已经看出了pytest和unitest的区别:
1.自动识别测试用例(unittest当中,需要引入TestSuite,主动加载测试用例。)
2.更加简单的断言表达:assert 表达式即可(unittest当中,self.assert*)
3.测试用例不需要封装在测试类当中(unittest中需要自定义类并继承TestCase)
pytest 简单示例2:pytest -v 可以显示详细的运行状况

import random

def test_demo1():
    """
    pytest  简单示例1
    """
    assert 5 == random.randint(1,10)

def test_demo2():
    """
    pytest  简单示例1
    """
    assert 1 == 1

def test_demo3():
    """
    pytest  简单示例1
    """
    assert 3 == 2

命令行运行结果:

pytest提供了很多运行参数,比较常用的有
-k:只执行指定的用例
-s:命令行显示测试代码的输出,如果需要输出html结果最好不要-s
-v:显示详细信息
-q:不显示详细信息
--html=path:输出测试结果到html
--lf:显示错误用例详细信息
这里举两个例子
1.这里如果要指定运行某个模块下某个py文件,在pytest -v  后追加模块名加py文件名
eg:pytest -v jirkou/test_demo.py
2.如果要看错误用例pytest --lf

 拿首页v8接口来举例子,让大家看到unitets和pytest的区别
1.case部分

unitest


#test_index_v8.py
import unittest
import requests


class Index_V8(unittest.TestCase):
    '''
    首页index_v8接口
    '''
    host = 'https://backend.igengmei.com'
    uri = '/api/index/v8'
    url = host + uri
    common_params = {
        "version": "7.24.0",
        "device_id": 1234,
        "current_city_id": "beijing"
    }

    def test_index_v8(self):
        '''
        :return: user self.assert to check
        '''
        self._testMethodDoc = '获取首页index_v8接口'
        res = requests.get(url=self.url, params=self.common_params)
        data = res.json()
        self.assertEqual(data['error'], 0,'error校验错误!' )


if __name__ == '__main__':
    unittest.main()

2.main部分

from unittest import defaultTestLoader
from BeautifulReport import BeautifulReport
# import pickle

if __name__ == '__main__':
    suites = defaultTestLoader.discover('testCase') #采集所有suites
    result = BeautifulReport(suites)  #定义一个result实例
    result.report('API自动化测试', 'gmapi_report.html', 'testReport') #跑

pytest就这一步就搞定,直接执行便可以

import requests


def test_index_v8():
    """
    pytest  简单示例1
    """
    host = 'https://backend.igengmei.com'
    uri = '/api/index/v8'
    url = host + uri
    common_params = {
        "version": "7.24.0",
        "device_id": 1234,
        "current_city_id": "beijing"
    }

    testMethodDoc = '获取首页index_v8接口'
    res = requests.get(url=url, params=common_params)
    data = res.json()
    assert(data['error'], 1,'error校验,,,,,错误!' )


2.在pytest的测试框架中,测试固件有各种形式的表现。
讲两大常用模块:初始化与清理与强大的参数化的部分
1.初始化与清理
setup_function、teardown_function
setup_module、teardown_module setup
teardown setup_class、teardown_class
setup_method、teardown_method
@pytest.fixture()

这里初始化与清理的方法有些class用例集可用有些def用例可用,并且要区分怎么使用。

class用例集类来说:
setup_function、teardown_function 不能用
setup_module、teardown_module 放在类外可以使用、放在类内不能使用,只在最前和最后调用
setup、teardown 放在类内可以使用、放在类外不能使用,每个case都会调用
setup_class、teardown_class 放在类内可以使用、放在类外不能使用,每个case都会调用
setup_method、teardown_method 放在类内可以使用、放在类外不能使用,每个case都会调用
@pytest.fixture() 放在类内类外都可以使用

对于def用例来说
setup_function、teardown_function 可以使用,每个case都会调用,无需成对使用
setup_module、teardown_module 可以使用,只在最前和最后调用
setup、teardown 可以使用,每个case都会调用
setup_class、teardown_class 不能用
setup_method、teardown_method 不能用
@pytest.fixture() 可以使用

那只有一个放在类内类外都可以使用,且只有pytest拥有,那就是最后一个@pytest.fixture()
详细讲解@pytest.fixture()

@pytest.fixture()是一个装饰器,用于声明函数是一个fixture
如果测试函数的参数中包含fixture名字,那么pytest会检测到
fixture 可以执行测试任务,也可以返回数据给测试函数

命令:pytest --setup -show py文件名,可以查看顺序
  pytest --setup-show jirkou/test_demo1.py

fixture()函数放在哪里合适?

1.放在单独的测试文件里
2.如果希望多个测试文件共享fixture,可以在某个公共目录下新建一个conftest文件,讲fixture放在里面

使用装饰器:pytest.fixture(scope='function',autouse=False)

fixture()函数参数解释说明

  fixture里面有个scope参数可以控制fixture的作用范围:session>module>class>function

  -function:每一个函数或方法都会调用

  -class:每一个类调用一次,一个类中可以有多个方法

  -module:每一个.py文件调用一次,该文件内又有多个function和class

  -session:是多个文件调用一次,可以跨.py文件调用,每个.py文件就是module
 

"""
    pytest 参数化以及作用范围function
"""
import pytest

@pytest.fixture(scope="function")
def get_username():
    print("\n获取用户名:")
    a = "yuanyuan"
    return a

@pytest.fixture()
def get_pwd():
    print("\n获取密码:")
    b = "123456"
    return b

def test_case1(get_username,get_pwd):
    """
    测试数据传测试用例fixture
    """
    print("测试账号%s"%get_username)
    assert get_username == "yuanyuan"
    assert get_pwd == "123456"

def test_case2(get_pwd):
    print("测试密码%s"%get_pwd)
    assert get_pwd == "123456"





"""
    pytest 参数化以及作用范围class
"""


import pytest

@pytest.fixture(scope="class")
def get_username():
    print("\n获取用户名:")
    a = "yuanyuan"
    return a

@pytest.fixture(scope="class")
def get_pwd():
    print("\n获取密码:")
    b = "123456"
    return b


class TestCase():
    
    def test_case1(self,get_username,get_pwd):
        """
        测试数据传测试用例fixture
        """
        print("测试账号%s"%get_username)
        assert get_username == "yuanyuan"
        assert get_pwd == "123456"


"""
    pytest 参数化以及作用范围module
    每一个.py文件调用一次,该文件内又有多个function和class
"""

"""
    pytest 参数化以及作用范围
"""
import pytest

@pytest.fixture(scope="module")
def get_username():
    print("\n获取用户名:")
    a = "yuanyuan"
    return a

@pytest.fixture(scope="module")
def get_pwd():
    print("\n获取密码:")
    b = "123456"
    return b


class TestCase():

    def test_case1(self,get_username,get_pwd):
        """
        测试数据传测试用例fixture
        """
        print("测试账号%s"%get_username)
        assert get_username == "yuanyuan"
        assert get_pwd == "123456"


def test_case2(get_pwd):
    """
           测试数据传测试用例fixture
           """
    print("测试密码%s"%get_pwd)
    assert get_pwd == "123456"
import pytest
import requests
import random


@pytest.fixture( scope='function')
def simple_request():
    return 55

def test_request(simple_request):
    assert simple_request == 55
@pytest.fixture( scope='function')
def simple_request():
    print('开始初始化')
    yield
    after_test()

def after_test():
    print('开始清除')
# autoust=False,添加初始化操作函数名作为参数,就会执行初始化操作,不加则不执行  scope='function'

def test_request(simple_request):
    print('测试用例1,开始执行测试')

def test_request2(simple_request):
    print('测试用例2,开始执行测试')
    assert 1 == 1

def test_demo1():
    """
    pytest.fixture()初始化简单示例1
    """
    print('测试用例3,开始执行测试')
    assert 5 == random.randint(4,5)

if __name__ == '__main__':
    pytest.main(["-s"])   #-s 为了能看见print的输出效果

运行结果:

collecting ... collected 3 items

test_demo1.py::test_request 开始初始化
PASSED                                [ 33%]测试用例1,开始执行测试
开始清除

test_demo1.py::test_request2 开始初始化
PASSED                                [ 66%]测试用例2,开始执行测试
开始清除

test_demo1.py::test_demo1 FAILED      [100%]测试用例3,开始执行测试


2.强大的参数化的部分

1.@pytest.fixture,在fixture级别的function参数化

 fixture是在测试函数运行前后,由pytest执行的外壳函数。首先来看fixture的函数返回值,也就是返回数值。

先看如下的案例代码:

import pytest
import requests
import random


@pytest.fixture( scope='function')
def simple_list():
    return [1,44,5,3]

def test_demo(simple_list):
    """
       参数化的简单示例
    """
    assert simple_list[1] == 44
import pytest
import requests
import logging

par_to_test=[{
    "case":"search a words:pytest",
    "headers":{},
    "querystring":{
        "version": "7.24.0",
        "device_id": "7A76480B-0192-4787-AB1A-93F7B9E606FF",
        "current_city_id": "beijing"
    },
    "payload":{},
    "status_code":200
}]

@pytest.fixture(params=par_to_test)
def case_deta(request):
    print(request.param)
    return request.param

def test_case_search(case_deta):
    url = "https://backend.igengmei.com/api/index/v7"
    logging.captureWarnings(True)
    res = requests.request("GET",url,headers=case_deta["headers"],params=case_deta["querystring"], verify=False)
    assert res.status_code == case_deta["status_code"]

还是一样,如果希望多个测试文件共享fixture,可以在某个公共目录下新建一个conftest文件,将fixture放部分在里面
2.@pytest.mark.parametrize() 允许在function或class级别的参数化,为特点的测试函数或类提供类多个argument/fixture设置

import pytest

def add(x,y):
    return x+y

@pytest.mark.parametrize(
    "x,y,expected",
    [
        (1,1,2),
        (2,2,4),
        (10,10,20),
    ]
)
def test_add(x,y,expected):
    assert add(x,y) == expected

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值