资讯专栏INFORMATION COLUMN

flask 单元测试 (一)

syoya / 1345人阅读

框架选择:

根据 https://blog.zengrong.net/pos...
得知:
flask项目本身使用的是pytest
nose是对标准库unittest的封装,现在比较流行,但文档没有pytest做的好,且近几年一直处于维护状态没有更新。
Flask-Testing flask扩展
最终选择:pytest

pytest 特点:

非常容易上手,入门简单,文档丰富,文档中有很多实例可以参考

能够支持简单的单元测试和复杂的功能测试

支持参数化

执行测试过程中可以将某些测试跳过,或者对某些预期失败的case标记成失败

支持重复执行失败的case

支持运行由nose, unittest编写的测试case

具有很多第三方插件,并且可以自定义扩展

方便的和持续集成工具集成

在命令行输入如下命令检查pytest是否已安装

py.test --version

如果没有

pip install -U pytest
第一个例子:测试函数
# content of test_sample.py


def func(x):
    return x+1


def test_func():
    assert func(3) == 5

运行:
执行测试时需要下面几步:

从命令行进入测试文件所在目录,pytest会在该目录中寻找以test开头的文件

找到测试文件,进入测试文件中寻找以test_开头的函数并执行

测试函数以断言assert结尾

$ py.test
============================= test session starts ==============================
platform darwin -- Python 3.5.1, pytest-2.8.1, py-1.4.30, pluggy-0.3.1
rootdir: /Users/fc/project/test/pytest_sample, inifile:
collected 1 items

test_sample.py F

=================================== FAILURES ===================================
__________________________________ test_func ___________________________________

    def test_func():
>       assert func(3) == 5
E       assert 4 == 5
E        +  where 4 = func(3)

test_sample.py:9: AssertionError
=========================== 1 failed in 0.01 seconds ===========================
第二个例子: 测试类
# content of test_class.py


class TestClass(object):
    def test_one(self):
        x = "this"
        assert "h" in x

    def test_two(self):
        x = "hello"
        assert hasattr(x, "check")

运行
下面的-q是 quiet的意思,就是忽略一些很细节的信息
使用测试类时,注意下面几点:

测试类所在的文件以test_开头

测试类以Test开头,并且不能带有__init__方法

类中测试函数以test_开头

测试函数以assert断言结尾

bogon:pytest_sample fc$ py.test -q test_class.py
.F
=================================== FAILURES ===================================
______________________________ TestClass.test_two ______________________________

self = 

    def test_two(self):
        x = "hello"
>       assert hasattr(x, "check")
E       assert hasattr("hello", "check")

test_class.py:11: AssertionError
1 failed, 1 passed in 0.01 seconds
第三个例子:参数化测试函数
import pytest

params = [
    (2, 3, 5),
    (4, 5, 9),
    (6, 7, 12)
]


@pytest.mark.parametrize("a, b, expected", params)
def test_add(a, b, expected):
    assert a + b == expected

运行结果

$ py.test -q test_params.py
..F
=================================== FAILURES ===================================
_______________________________ test_add[6-7-12] _______________________________

a = 6, b = 7, expected = 12

    @pytest.mark.parametrize("a, b, expected", params)
    def test_add(a, b, expected):
>       assert a + b == expected
E       assert (6 + 7) == 12

test_params.py:12: AssertionError
1 failed, 2 passed in 0.01 seconds

说明:

params是要进行测试的参数list,其中元素为tuple,每个tuple对应一套参数

@pytest.mark.parametrize装饰器的第一个参数是一个字符串,不过这个字符串其实是以逗号分隔的一组参数,这个参数就是其所装饰的函数的参数。

@pytest.mark.parametrize装饰器将params中的参数一套一套拿出来放入其所装饰的函数中执行

第四个例子 fixture params
import pytest


@pytest.fixture(params=[1, 2, 3])
def test_data(request):
    return request.param


def test_not_2(test_data):
    assert test_data != 2

运行结果:

$ py.test -q fixture_params.py
.F.
======================================= FAILURES =======================================
____________________________________ test_not_2[2] _____________________________________

test_data = 2

    def test_not_2(test_data):
>       assert test_data != 2
E       assert 2 != 2

fixture_params.py:10: AssertionError
1 failed, 2 passed in 0.01 seconds

说明:

把一个函数定用@pytest.fixture装饰,那这个函数就是fixture函数

一个fixture函数可以被其他测试函数调用,将函数名当作参数即可,fixture的返回值会当作测试函数的参数

fixture函数中的params字段默认为None,如果有值,则每个值都会调用执行一次

在flask项目中使用pytest flask应用demo代码
from flask import Flask


app = Flask(__name__)


@app.route("/")
def index():
    return "hello"


@app.route("/login")
def login():
    return "login"


@app.route("/logout")
def logout():
    return "logout"


@app.errorhandler(404)
def page_not_found():
    return "404"


if __name__ == "__main__":
    app.run()
flask demo的测试代码
from flaskr import app


class TestClass(object):
    def setup_class(self):
        """测试开始时候执行, 用来做准备工作,一般用来初始化资源。"""
        app.config["TESTING"] = True  # 这将会使得处理请求时的错误捕捉失效,以便于 您在进行对应用发出请求的测试时获得更好的错误反馈。
        # 测试客户端将会给我们一个通向应用的简单接口,我们可以激发 对向应用发送请求的测试,并且此客户端也会帮我们记录 Cookie 的 动态。
        self.app = app.test_client()

    def teardown_class(self):
        """测试结束时执行, 用来做收尾工作, 一般用来关闭资源"""
        pass

    def test_login(self):
        response = self.app.get("/login")
        assert b"login" == response.data

    def test_logout(self):
        response = self.app.get("logout")
        assert b"logout" == response.data

    def test_index(self):
        response = self.app.get("/")
        assert b"hello" == response.data

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/41232.html

相关文章

  • Flask Web Development —— 大型应用程序结构(下)

    摘要:单元测试这个应用非常小以至于不需要太多的测试,但是作为示例会在示例中展示两个简单的测试定义。示例单元测试编写好的测试使用的是来自于标准库中标准的包。为了运行单元测试,可以在脚本中增加一个自定义的命令。 4、启动脚本 顶层目录中的manage.py文件用于启动应用。这个脚本会在示例7-8中展示。 示例7-8. manage.py:启动脚本 #!/usr/bin/env python im...

    whidy 评论0 收藏0
  • Flask Web 测试驱动开发最佳实践之 Flask 实例

    摘要:当功能越来越复杂的时候,你可能修改了一些东西,导致另外一个功能的不可用,而单元测试也能保证了原有功能被破坏后能被检测出来。 showImg(https://segmentfault.com/img/remote/1460000017081749); 前言 前一篇讲到了 TDD 测试驱动开发的相关概念和环境搭建,这篇就着手开始用TDD方式开发了。首先这篇需要编写用户相关的API接口,如...

    wuyangnju 评论0 收藏0
  • 02-Flask-用户认证和角色管理-数据库设计

    摘要:认证管理新建数据库需要的插件用来发送认证信息用于管理用于密码加盐表单对象创建渲染建立认证蓝图建立用户模型权限分配权限等级设置直接新建一个对象来表示权限设置三种用户角色角色权限描述只读基础权限只有一个修改评论权限多一个管理员权限建 认证管理 新建数据库 create database `flasky` default character set utf8 collate utf8_gen...

    noONE 评论0 收藏0
  • 精选50道Python面试题,快来看看你已经掌握了多少道吧

    摘要:从存储的字符串表示中检索原始对象的过程称为。这称为命名空间。如果需要八进制或十六进制表示,请使用内置函数或。和有什么区别返回对象,而返回列表,并使用相同的内存,无论范围大小是多少。它提供了灵活性,并允许开发人员为他们的项目使用正确的工具。 ...

    zzir 评论0 收藏0
  • microservices-with-docker-flask-and-react 简介

    摘要:前置条件这不是一个入门课程。此课程为至少有六个月网站开发经验的高级入门者设置。主题资源目标这部分结束,具备以下能力。。。第一部分完整代码依赖第一部分依赖耗时一章需要几个小时到一整天。空余大块时间来完成一章,特别是,,这些较难的部分。 在第一部分, 你学到如何使用 Docker 来创建一个基于python, postgres, 和 flask web 框架的 RESTful API 可重...

    lily_wang 评论0 收藏0

发表评论

0条评论

syoya

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<