< a href="https://github.com/%E5%B0%8F%E7%9A%AE%E6%B5%A9"> Fork me on GitHub

测试接口及pytest

<!doctype html>

测试接口

测试接口

import requests
except = {'title':'V2EX'}
response = requests.get(url='https://www.v2ex.com/api')

if response.json()['title'] == except['title']:
print('断言成功')
assert 1
else:
print('断言失败')
assert 0

pytest

pytest使用手册:https://learning-pytest.readthedocs.io/zh/latest/

定义:

是python的单元测试框架

特点:

  1. 入门简单易上手,文档支持好
  2. 支持单元测试和功能测试
  3. 支持参数化
  4. 可以跳过指定用例,或对某些预期失败的case标记成失败
  5. 支持重复执行失败的case
  6. 支持运行由unittest编写的测试用例
  7. 有很多第三方插件,并且可自定义扩展。
  8. 方便和支持继承工具进行集成

 

下载install pytest

测试之前的准备

M:\py_tests\ # 我的是M盘的 py_tests 目录,所有操作都在 py_tests 目录内完成
    ├─scripts   
    │  ├─test_case_dir1
    │  │  ├─test_case_02.py    # 用例脚本文件
    │  │  └─__init__.py
    │  ├─test_allure_case.py   # 脚本文件
    │  ├─test_case_01.py   # 脚本文件
    │  └─__init__.py
    ├─report
    │  ├─report.html   # pytest-html生成的用例报告
    │  ├─assets  # allure的依赖目录
    │  ├─result  # allure生成的用例数据
    │  └─allure_html   # allure生成的用例报告目录
    |     └─index.html  # allure生成的最终的html类型的测试报告  
    ├─case_set.py
    ├─demo0.py   # 用例脚本文件
    ├─demo1.py   # 用例脚本文件
    ├─pytest.ini  # 配置文件
    └─__init__.py

简单示例

启动pytest框架方式

方式一:

直接执行py文件

import requests
import pytest

expect ={'title':'V2EX'}

def test_case_01():
response = requests.get(url='https://www.v2ex.com/api/site/info.json')
print(response.json())

if response.json()['title'] == expect['title']:
print('断言成功')
assert 1
else:
print('断言失败')

if name == 'main':
pytest.main(['-s','run.py'])

pytest只执行test开头的用例,所以用例必须是test开头的函数

如何或去当前脚本中所有的变量或函数:

ptint(dir())   #获取当前脚本中所有的变量

demo1.py

import pytest

def test_case01():
print('执行用例01.........')
assert 0 #断言失败

断言就是做出判断的语言,断言成功就是,将用例设置为成功,即断言成功

def test_case02():
print("执行用例02........")
assert 1 #断言成功

def custom_case03():
print("执行用例03.........")
assert 1 #断言成功
if name == "main":
pytest.main(["-s","demo1.py"])

上述代码执行之后结果:

E:\pycharm\解释器\python.exe F:/测试/day75/demo1.py
============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-5.3.2, py-1.8.0, pluggy-0.13.1
rootdir: F:\测试\day75
collected 2 items    #表示执行2个用例

demo1.py 执行用例01.........
F执行用例02........ #F表示用例执行失败
. #.表示该用例执行成功

================================== FAILURES ===================================
_________________________________ test_case01 _________________________________

报错信息,和错误位置

def test_case01():
print('执行用例01.........')
> assert 0 # 断言失败
E assert 0

demo1.py:6: AssertionError
========================= 1 failed, 1 passed in 0.11s =========================

Process finished with exit code 0

脚本中的第一个用例执行失败;第二个用例执行成功;但是第三个也就是custom_case03并没有执行,由此知道pytest只识别以test_开头的用例

pytest.main(["-s","demo1.py"])参数说明

-s:表示输出用例的详细结果

demo1.py表示要执行的脚本名称

 

用例类的写法:

import pytest
class TestCase(object):
    def test_case01(self):
        """用例01"""
        print('执行用例01')
        assert 0  #断言失败

def test_case02(self):
"""用例02"""
print('执行用例02')
assert 1 #断言成功

if name=='main':
pytest.main(["-s","demo1.py"])

用法和unittest差不多,类名要以Test开头,并且其中的用例方法也要以test开头,然后执行也一样

setup和teardown

模块级别,也就是在整个测试脚本中的用例集执行前后,对应的是:

setup_module

teardown_moule

import pytest
def teardown_module():
    print('模块断开数据连接')

def setup_module():
print('建立数据库连接连接成功')

def test_cese_01():
print('用例函数郭建凯的成功啦')
assert 1
class TestCase(object):

def test_cese_01(self):
print('用例类模块1郭建凯的成功啦')
assert 1

if name == 'main':
pytest.main(['-s','run.py'])

执行顺序为:

1 setup_module()

2 test_case_01()

3 class TestCase(object)

4 teardown_module()

 

函数级别的,也就是在测试用例函数执行前后,对应的是:

函数级别的,不参与类的用例,只对函数用例有效

setup_function

teardown_function

实例:

import pytest
def teardown_function():
    print('断开数据连接')

def setup_function():
print('建立数据库连接连接成功')

def test_cese_01():
print('郭建凯的成功啦')
assert 1

if name == 'main':
pytest.main(['-s','run.py'])

上述执行顺序为:先执行

1 setup_function()

2 test_case_01()

3 teardown_function()

类级别的,也就是测试用例类前后,对应的是

setup_class()

teardown_class()

import pytest
def teardown_module():
    print('模块断开数据连接')

def setup_module():
print('建立数据库连接连接成功')

def test_cese_01():
print('用例函数郭建凯的成功啦')
assert 1
class TestCase(object):

def setup_class(self):
print('类级别的setup')

def teardown_class(self):
print('类级别的teardown')

def test_cese_01(self):
print('用例类模块1郭建凯的成功啦')
assert 1

if name == 'main':
pytest.main(['-s','run.py'])

执行顺序为:

1 def setup_module()

2 def test_case_01()

3 def setup_class(self)

4 def test_case_01(self)

5 def teardown_class(self)

6 def teardown_module()

类方法级别的,在每个类方法前后执行

setup_mothod

teardown_mothod

知识点补充:

import sys
def foo():
    print('fooo.......')
if 'foo' in dir():
    getattr(sys.modules[__name__].'foo')()
#反射getattr寻找脚本中有没有foo这个函数,有就执行

配置文件

pytest.ini

[pytest]
addopts = -s -v --html=report/report.html --alluredir ./report/result
testpaths = ./scripts
python_files = test_*.py   #如果将test_*改为test_login.py,只执行脚本test_login.py
python_classes = Test*
python_functions = test_*
xfail_strict=true   #我们将预期失败,结果却执行成功了的用例标记为执行失败

注意:在创建自动化脚本时py文件不能是有中文

skip(跳过用例)

class TestCase(object):

def setup_class(self):
print('类级别的setup')

def teardown_class(self):
print('类级别的teardown')
@pytest.mark.skip(condition=True,reason='用例1')
#这是用例无条件跳过
def test_cese_01(self):
print('用例类模块1郭建凯的成功啦')
assert 1
def test_cese_02(self):
print('用例类模块2跳过测试成功啦')
assert 1

class TestCase(object):

    def setup_class(self):
        print('类级别的setup')

    def teardown_class(self):
        print('类级别的teardown')
    @pytest.mark.skipif(condition=True,reason='用例1')
    #这是只有当condition属性为真时用例跳过
    def test_cese_01(self):
        print('用例类模块1郭建凯的成功啦')
        assert 1
    def test_cese_02(self):
        print('用例类模块2跳过测试成功啦')
        assert 1

如果想要跳过整个类,在类前加入

@pytest.mark.skip(condition=True,reason='用例类')
class TestCase(object):

def setup_class(self):
print('类级别的setup')

def teardown_class(self):
print('类级别的teardown')
@pytest.mark.skipif(condition=True,reason='用例1')
#这是只有当condition属性为真时用例跳过
def test_cese_01(self):
print('用例类模块1郭建凯的成功啦')
assert 1
def test_cese_02(self):
print('用例类模块2跳过测试成功啦')
assert 1

标记预期

如果我们事先知道测试函数会执行失败,但又不想直接跳过,而是希望显示的提示

预期失败,但实际结果却执行成功

预期失败,实际结果也执行失败

pytest使用pytest.mark.xfail

用例

import pytest

class TestCase(object):

def setup_class(self):

print('类级别的setup')

def teardown_class(self):

print('类级别的teardown')

@pytest.mark.xfail(condition=True,reason='xxx')
def test_cese_01(self):
"""预期失败,实际成功"""
assert 1

@pytest.mark.xfail(condition=True,reason='oo')
def test_cese_02(self):
"""预期失败,实际失败"""
assert 0

结果:

scripts/test_case.py::TestCase::test_cese_01 FAILED
#FAILED   是表标记为失败,实际执行成功,因为配置文件设置后,也会执行失败
scripts/test_case.py::TestCase::test_cese_02 XFAIL
#XFAIL    是表示标记失败,实际执行也失败
scripts/test_case.py::TestCase::test_cese_01 XPASS
#XPASS是没有设置位置文件,标记失败,执行却成功了

参数化

@pytest.mark.parametrize("mobile",l) 作用是遍历列表中的每一个元素作为参数传给用例,在用例中断言

import requests
import pytest

l = [
{"url": "https://www.v2ex.com/api/site/info.json", "expect": {"title": "V3EX"}},
{"url": "https://cnodejs.org/api/v1/topics", "expect": {"success": True}}
]

li = [100086,10010,110,120]

@pytest.mark.parametrize("mobile",l)

作用是遍历列表中的每一个元素作为参数传给用例,在用例中断言

def test_case(mobile):
response = requests.get(url=mobile['url'])
for title in mobile['expect']:
if mobile['expect'][title] != response.get(title,None):
assert mobile['expect'][title] != response.get(title,None)
else:
assert mobile['expect'][title] == response.get(title,None)

固件

固件(Fixture)是一些函数,pytest会在执行测试函数之前(或者之后)家在运行他们,也称夹具

我们可以利用固件做任何事情,其中最常见的可能就是数据库的初始链接和最后关闭操作

使用pytest.fixture()定义固件,下面是最简单的固件,访问主页前,必须先登录:

@pytest.fixture(scope="function")
def login():
    print('登录')

def test_index1(login):
print('主页1')

def test_index2(login):
print('主页2')

作用域

在之前实例中,你可能会觉得,这跟setup和teardown的功能类似,但是fixture相对于setup

和teardown来说更灵活pytest通过scope参数来控制固件的适用范围,也就是作用域

在定义固件时,通过scope参数来控制固件的适用范围,也就是作用域。

在定义固件时,通过scope参数声明作用域,可选项有:

function:函数级,每个测试函数都会执行一次固件

class:类级别,每个测试类执行一次所有方法都可以使用

module:模块级,每个模块执行一次,模块内函数和方法都可以使用;

session:会话级,一次测试只执行一次,所有被找到的函数和方法都可以用

默认作用域是function

预处理和后处理

很多时候需要在测试前进行预处理(如新建数据库连接),并在测试完成进行清理(关闭数据库连接)。

当有大量重复的这类操作,最佳实践是使用固件来自动化所有预处理和后处理。

Pytest 使用 yield 关键词将固件分为两部分,yield 之前的代码属于预处理,会在测试前执行;yield 之后的代码属于后处理,将在测试完成后执行。

以下测试模拟数据库查询,使用固件来模拟数据库的连接关闭:

import pytest

@pytest.fixture()
def db():
print('Connection successful')

yield

print('Connection closed')

def search_user(user_id):
d = {
'001': 'xiaoming',
'002': 'xiaohua'
}
return d[user_id]

def test_case_01(db):
assert search_user('001') == 'xiaoming'

def test_case_02(db):
assert search_user('002') == 'xiaohua'

结果:

M:\py_tests>pytest                    

scripts/test_case_01.py::test_case_01 Connection successful
PASSEDConnection closed

scripts/test_case_01.py::test_case_02 Connection successful
PASSEDConnection closed

====================================================== 2 passed in 0.15s =======================================================

可以看到在两个测试用例执行前后都有预处理和后处理。

常用插件

pytest中还有非常多的插件供我们使用,我们来介绍几个常用的。

先来看一个重要的,那就是生成测试用例报告。

pytest测试报告插件

想要生成测试报告,首先要有下载,才能使用。

下载

pip install pytest-html

https://github.com/pytest-dev/pytest-html

如果下载失败,可以使用PyCharm下载,怎么用PyCharm下载这里无需多言了吧。

使用

在配置文件中,添加参数:

[pytest]
addopts = -s --html=report/report.html

完事之后,让我们继续终端中使用pytest重新跑测试用例,用例结果就不展示了,跟上面的结果一样,我们关注项目目录下的report/report.html文件,我们用浏览器打开它,你会发现:

 

allure框架

终端执行allure的语句

allure generate report/result -o report/allure_html --clean

 

 

 

 

 

posted @ 2019-12-28 15:46  赌徒!  阅读(157)  评论(0)    收藏  举报