pytest用于flask项目数据模型单元测试

项目目录结构

│  .coverage
│  config.py
│  manage.py
│  README.md
│  requirements.txt
│  setup.cfg
│  tree.txt
├─instance
├─migrations    
├─mytools
│  │  extensions.py
│  │  logger.py
│  │  models.py
│  │  __init__.py
│  │  
│  ├─logs
│  │      assistant.log    
├─tests
│  │  conftest.py
│  │  test_db.py
│  │  test_scope.py
│  │  
│  ├─data
│  │      setup.sql
│  │      teardown.sql

借助功能齐全的pytest测试框架,编写了一套mysql数据表的测试框架,实现了数据与用例分离,数据批量初始化、销毁,简单易用。

核心模块conftest.py简介

conftest.py

#!/usr/bin/env python
# encoding: utf-8
"""
@author: wanwei
@license: (C) Copyright 2013-2017, Node Supply Chain Manager Corporation Limited.
@software: pycharm
@file: conftest.py
@time: 2019/9/24 11:02
@desc:
"""
import pytest
import os
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../')))

from mytools import create_app
from mytools.extensions import db

# 加载数据初始化SQL语句文件
with open(os.path.join(os.path.dirname(__file__), './data/setup.sql'), 'rb') as f:
    _setup_sql = f.readlines()

# 销毁数据SQL语句文件
with open(os.path.join(os.path.dirname(__file__), './data/teardown.sql'), 'rb') as f:
    _teardown_sql = f.readlines()


@pytest.fixture(scope='session')
def setup(request):
    def teardown():
        print("用例执行结束..................................")
    request.addfinalizer(teardown)
    print("用例执行开始..................................")

@pytest.fixture(scope="module")
def setup_database(request):
    print("setup tb_user开始执行...............")
    # ----------FLASK-SQLALCHEMY数据库配置---------#
    USERNAME = 'root'
    PASSWORD = '123456'
    HOST = '127.0.0.1'
    DB = 'mockservertest'

    SQLALCHEMY_DATABASE_URI = 'mysql+mysqlconnector://%s:%s@%s/%s' % (USERNAME, PASSWORD, HOST, DB)
    # 创建应用实例
    app = create_app({
        'TESTING': True,
        # 数据库文件存放路径
        'SQLALCHEMY_DATABASE_URI': SQLALCHEMY_DATABASE_URI,
        'SQLALCHEMY_TRACK_MODIFICATIONS': False,
        'SQLALCHEMY_ECHO': False
    })
    def teardown_database():
        print("teardown tb_user开始执行...............")
        with app.app_context():
            #初始化数据库模型
            db.create_all()
            for sql in _teardown_sql:
                if sql:
                    db.engine.execute(sql.decode('utf-8'))
    request.addfinalizer(teardown_database)
    with app.app_context():
        for sql in _setup_sql:
            if sql:
                db.engine.execute(sql.decode('utf-8'))


@pytest.fixture(scope='function')
def setup_function(request):
    def teardown_function():
        print("teardown_function called...")
    request.addfinalizer(teardown_function)  # 内嵌函数做teardown操作
    print("setup_function called...")


@pytest.fixture(scope='module')
def setup_test(request):
    def teardown_test():
        print("teardown_module called...")
    request.addfinalizer(teardown_test)
    print("setup_module called...")

从上面的代码来看,fixture具备以下优势:

  • 命名方式灵活,不局限于setup和teardown这几个命名,装饰器@pytest.fixture下可以自定义fixture函数,命名可以根据使用场景来自定义
  • conftest.py 配置里可以实现数据共享,不需要import就能自动找到一些配置,运行pytest,即可自动导入
  • scope=“module” 可以实现多个.py跨文件共享前置, 一次引入,该用例.py文件调用一次
  • scope=“session” 一次引入,多个.py跨文件使用一个session来完成多个用例模块py文件的数据初始化和销毁

conftest.py配置需要注意以下点:

  • conftest.py配置脚本名称是固定的,不能改名称,即名称必须是conftest.py
  • conftest.py与运行的用例要在同一个pakage下,并且有__init__.py文件
  • 不需要import导入 conftest.py,pytest用例会自动查找

数据初始化文件

│  ├─data
│  │      setup.sql
│  │      teardown.sql

借助conftest.py可轻松实现数据与用例分离
setup.sql

INSERT INTO `tb_user`(password_hash,username,lastseen) VALUES ('pbkdf2:sha256:150000$3mEwvVlo$8f98a0ba2576529e7cd379eaea723bd2195ad1882d480150ff4736a5ed05a260', 'wanwei', '2019-9-18 14:59:43');
INSERT INTO `tb_user`(password_hash,username,lastseen) VALUES ('pbkdf2:sha256:150000$P2sZt9ih$d4ef4d800c4ae7a139fae3a389bbddab6789e7524bd976ab5914945bc52d0f59', 'wanwei2', '2019-9-23 20:08:49');

teardown.sql

DELETE FROM `tb_user` WHERE username='wanwei';
DELETE FROM `tb_user` WHERE username='wanwei2';

测试用例

测试用例具备以下特点:

  • 测试用例文件以test_开头或以_test结尾
  • 引入fixture,只需在测试函数参数列表中传入fixture名称即可
    test_db.py
#!/usr/bin/env python
# encoding: utf-8
"""
@author: wanwei
@license: (C) Copyright 2013-2017, Node Supply Chain Manager Corporation Limited.
@software: pycharm
@file: test_db.py
@time: 2019/9/24 13:46
@desc:
"""
from mytools.models import User
from mytools.extensions import db
from mytools import app


def test_password_hash(setup):
    """测试密码加密"""
    u = User(username="wanwei3")
    u.set_password("sdfg")
    assert u.check_password("sdfg") is True
    assert u.check_password("huwe") is False


def test_follow(setup_database):
    """测试关注函数"""
    with app.app_context():
        user1 = User.query.filter_by(username='wanwei').first()
        user2 = User.query.filter_by(username='wanwei2').first()
        assert user1.username == 'wanwei','user1 username不正确'
        assert user2.username == 'wanwei2','user2 username不正确'

test_scope.py

#!/usr/bin/env python
# encoding: utf-8
"""
@author: wanwei
@license: (C) Copyright 2013-2017, Node Supply Chain Manager Corporation Limited.
@contact: wei_wan@sui.com
@software: pycharm
@file: pytest1.py
@time: 2019/9/29 15:29
@desc:
"""
import pytest


@pytest.mark.recommend
def test_1(setup_function):
    print("test_1 called...")


def test_2(setup_test):
    # assert 1 != 1
    print("test_2 called...")


def test_3(setup_test):
    print("test_3 called...")

测试配置文件setup.cfg

  • 与应用 app 同级,用于配置测试参数;
  • filterwarnings 用于忽略废弃提示;
  • testpaths 用于定义测试脚本所在目录;
  • source 设置 coverage 测试时的应用名称。
    setup.cfg
[tool:pytest]
filterwarnings =
    error
    ignore::DeprecationWarning
testpaths = tests

[coverage:run]
branch = True
source = mytools

测试运行

  • pytest,命令行输出一串点
  • pytest -v,命令行输出每个用例的列表
  • pytest -s,命令行可以输出用例执行的详细print函数打印信息
  • pytest 用例文件名,可以单独运行用例模块
  • pytest ./tests/test_scope.py::test_2,单独运行某个测试用例

使用coverage模块统计测试覆盖率

(mockenv) E:\技术资料\接口框架\datatestdemo>pytest ./tests/test_scope.py::test_2
============================================================================================ test session starts ============================================================================================
platform win32 -- Python 3.5.2, pytest-3.9.2, py-1.7.0, pluggy-0.8.0
rootdir: E:\技术资料\接口框架\datatestdemo, inifile: setup.cfg
plugins: metadata-1.7.0, html-1.19.0, cov-2.7.1, allure-adaptor-1.7.10
collected 1 item                                                                                                                                                                                             

tests\test_scope.py .                                                                                                                                                                                  [100%]

========================================================================================= 1 passed in 0.07 seconds ==========================================================================================

(mockenv) E:\技术资料\接口框架\datatestdemo>
(mockenv) E:\技术资料\接口框架\datatestdemo>
(mockenv) E:\技术资料\接口框架\datatestdemo>coverage run -m pytest
============================================================================================ test session starts ============================================================================================
platform win32 -- Python 3.5.2, pytest-3.9.2, py-1.7.0, pluggy-0.8.0
rootdir: E:\技术资料\接口框架\datatestdemo, inifile: setup.cfg
plugins: metadata-1.7.0, html-1.19.0, cov-2.7.1, allure-adaptor-1.7.10
collected 5 items                                                                                                                                                                                            

tests\test_db.py ..                                                                                                                                                                                    [ 40%]
tests\test_scope.py ...                                                                                                                                                                                [100%]

========================================================================================= 5 passed in 0.65 seconds ==========================================================================================

(mockenv) E:\技术资料\接口框架\datatestdemo>coverage report
Name                    Stmts   Miss Branch BrPart  Cover
---------------------------------------------------------
mytools\__init__.py        19      0      4      0   100%
mytools\extensions.py       7      0      0      0   100%
mytools\logger.py          13      1      2      1    87%
mytools\models.py          29      5      0      0    83%
---------------------------------------------------------
TOTAL                      68      6      6      1    91%

生成html报告

coverage html

在htmlcov目录中生成HTML报告,直接打开htmlcov/index.html 即可查看用例覆盖情况:
在这里插入图片描述
项目地址:
https://github.com/wanwei890116/Apitest

参考:
pytest文档5-fixture之conftest.py
https://www.cnblogs.com/yoyoketang/p/9390073.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值