FastAPI 的单元测试

  • 对于服务端来说,通常会对功能进行单元测试,也称白盒测试
  • FastAPI 集成了第三方库,让我们可以快捷的编写单元测试
  • FastAPI 的单元测试是基于 Pytest + Request 的

Pytest 学习

https://www.cnblogs.com/poloyy/tag/Pytest/

TestClient 简单的栗子

#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠萝测试笔记
# blog: https://www.cnblogs.com/poloyy/
# time: 2021/9/29 10:55 下午
# file: 37_pytest.py
"""
import uvicorn
from fastapi import FastAPI
from fastapi.testclient import TestClient app = FastAPI() @app.get("/")
async def read_main():
return {"msg": "Hello World"} # 声明一个 TestClient,把 FastAPI() 实例对象传进去
client = TestClient(app) # 测试用
def test_read_main():
# 请求 127.0.0.1:8080/
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"msg": "Hello World"} if __name__ == '__main__':
uvicorn.run(app="37_pytest:app", reload=True, host="127.0.0.1", port=8080)

在该文件夹下的命令行敲

pytest 37_pytest.py

运行结果

TestClient 的源码解析

继承了 requests 库的 Session

所以可以像使用 requests 库一样使用 TestClient,拥有 requests 所有方法、属性

重写了 Session.requests 方法

重写了 requests 方法,不过只是加了一句 url = urljoin(self.base_url, url) url 拼接代码,还有给函数参数都加了类型指示,更加完善啦~

自定义 websocket 连接方法

后面学到 webSocket 再详细讲他

重写了 __enter__、__exit__ 方法

  • Session 的这两个方法还是比较简陋的,TestClient 做了一次重写,主要是为了添加异步的功能(异步测试后面详解,这篇举栗子的都是普通函数 def)
  • 前面讲过有 __enter__、__exit__ 方法的对象都是上下文管理器,可以用 with .. as ..语句来调用上下文管理器

.get() 方法

上面代码 client.get(),直接调用的就是 Session 提供的 get() 方法啦!

复杂的测试场景

服务端

#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠萝测试笔记
# blog: https://www.cnblogs.com/poloyy/
# time: 2021/9/29 10:55 下午
# file: s37_pytest.py
"""
import uvicorn
from fastapi import FastAPI
from fastapi.testclient import TestClient app = FastAPI() @app.get("/")
async def read_main():
return {"msg": "Hello World"} # 声明一个 TestClient,把 FastAPI() 实例对象传进去
client = TestClient(app) # 测试用
def test_read_main():
# 请求 127.0.0.1:8080/
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"msg": "Hello World"} from typing import Optional from fastapi import FastAPI, Header, HTTPException
from pydantic import BaseModel # 模拟真实 token
fake_secret_token = "coneofsilence" # 模拟真实数据库
fake_db = {
"foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"},
"bar": {"id": "bar", "title": "Bar", "description": "The bartenders"},
} app = FastAPI() class Item(BaseModel):
id: str
title: str
description: Optional[str] = None # 接口一:查询数据
@app.get("/items/{item_id}", response_model=Item)
async def read_main(item_id: str, x_token: str = Header(...)):
# 1、校验 token 失败
if x_token != fake_secret_token:
raise HTTPException(status_code=400, detail="x-token 错误") # 2、若数据库没有对应数据
if item_id not in fake_db:
raise HTTPException(status_code=404, detail="找不到 item_id")
# 3、找到数据则返回
return fake_db[item_id] # 接口二:创建数据
@app.post("/items/", response_model=Item)
async def create_item(item: Item, x_token: str = Header(...)):
# 1、校验 token 失败
if x_token != fake_secret_token:
raise HTTPException(status_code=400, detail="x-token 错误") # 2、若数据库已经存在相同 id 的数据
if item.id in fake_db:
raise HTTPException(status_code=400, detail="找不到 item_id") # 3、添加数据到数据库
fake_db[item.id] = item # 4、返回添加的数据
return item if __name__ == '__main__':
uvicorn.run(app="s37_test_pytest:app", reload=True, host="127.0.0.1", port=8080)

单元测试

#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠萝测试笔记
# blog: https://www.cnblogs.com/poloyy/
# time: 2021/9/29 10:55 下午
# file: s37_pytest.py
"""
from fastapi.testclient import TestClient
from .s37_test_pytest import app client = TestClient(app) def test_read_item():
expect = {"id": "foo", "title": "Foo", "description": "There goes my hero"}
headers = {"x-token": "coneofsilence"}
resp = client.get("/items/foo", headers=headers)
assert resp.status_code == 200
assert resp.json() == expect def test_read_item_error_header():
expect = {"detail": "x-token 错误"}
headers = {"x-token": "test"}
resp = client.get("/items/foo", headers=headers)
assert resp.status_code == 400
assert resp.json() == expect def test_read_item_error_id():
expect = {"detail": "找不到 item_id"}
headers = {"x-token": "coneofsilence"}
resp = client.get("/items/foos", headers=headers)
assert resp.status_code == 404
assert resp.json() == expect def test_create_item():
body = {"id": "foos", "title": "Foo", "description": "There goes my hero"}
headers = {"x-token": "coneofsilence"}
resp = client.post("/items/", json=body, headers=headers)
assert resp.status_code == 200
assert resp.json() == body def test_create_item_error_header():
body = {"id": "foo", "title": "Foo", "description": "There goes my hero"}
expect = {"detail": "x-token 错误"}
headers = {"x-token": "test"}
resp = client.post("/items/", json=body, headers=headers)
assert resp.status_code == 400
assert resp.json() == expect def test_create_item_error_id():
expect = {"detail": "找不到 item_id"}
body = {"id": "foo", "title": "Foo", "description": "There goes my hero"}
headers = {"x-token": "coneofsilence"}
resp = client.post("/items/", json=body, headers=headers)
assert resp.status_code == 400
assert resp.json() == expect

命令行运行

pytest test.py -sq

运行结果

> pytest s37_pytest.py -sq
......
6 passed in 0.40s

FastAPI(43)- 基于 pytest + requests 进行单元测试的更多相关文章

  1. pytest+requests+Python3.7+yaml+Allure+Jenkins+docker实现接口自动化测试

    接口自动化测试框架(用例自动生成) 项目说明 本框架是一套基于pytest+requests+Python3.7+yaml+Allure+Jenkins+docker而设计的数据驱动接口自动化测试框架 ...

  2. 基于Python Requests的数据驱动的HTTP接口测试

    发表于:2017-8-30 11:56  作者:顾翔   来源:51Testing软件测试网原创 http://www.51testing.com/html/69/n-3720769-2.html   ...

  3. Appium 并发多进程基于 Pytest框架

    前言: 之前通过重写unittest的初始化方法加入设备参数进行并发,实现了基于unittest的appium多设备并发,但是考虑到unittest的框架实在过于简陋,也不方便后期的Jenkins的持 ...

  4. unit vs2017基于nunit framework创建单元测试

    unit  vs2017基于nunit framework创建单元测试 一.简叙: 单元测试大型项目中是必备的,所以不可忽视,一个项目的成败就看是否有单元测试,对后期的扩展维护都带来了便利. 二.安装 ...

  5. 基于Pytest豆瓣自动化测试【1】

    -- Pytest基础使用教程[1] 引言 Pytest 是一个非常实用的自动化测试框架,目前来说资料也是非常多了.最近某友人在学习 Python的一些测试技术,帮其网上搜了下教程:发现大多数文章多是 ...

  6. 基于Python+Requests+Pytest+YAML+Allure实现接口自动化

    本项目实现接口自动化的技术选型:Python+Requests+Pytest+YAML+Allure ,主要是针对之前开发的一个接口项目来进行学习,通过 Python+Requests 来发送和处理H ...

  7. 基于spring与mockito单元测试Mock对象注入

    转载:http://www.blogjava.net/qileilove/archive/2014/03/07/410713.html 1.关键词 单元测试.spring.mockito 2.概述 单 ...

  8. 【Pytest】python单元测试框架pytest简介

    1.Pytest介绍 pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高.根据pytest的官方网站介绍 ...

  9. 如何写好、管好单元测试?基于Roslyn+CI分析单元测试,严控产品提测质量

    上一篇文章中,我们谈到了通过Roslyn进行代码分析,通过自定义代码扫描规则,将有问题的代码.不符合编码规则的代码扫描出来,禁止签入,提升团队的代码质量. .NET Core技术研究-通过Roslyn ...

随机推荐

  1. springboot中@Mapper和@Repository的区别

    @Mapper和@Repository是常用的两个注解,两者都是用在dao上,两者功能差不多,容易混淆,有必要清楚其细微区别: 区别: @Repository需要在Spring中配置扫描地址,然后生成 ...

  2. Linux中的静态库与动态库

    什么是库文件? 库文件是事先编译好的方法的合集.比如:我们提前写好一些数据公式的实现,将其打包成库文件,以后使用只需要库文件就可以,不需要重新编写. Linux系统中: 1.静态库的扩展名为.a:2. ...

  3. UWP使用命名管道与桌面程序通信 (C#)

    关于UWP的历史,其起源是Microsoft在Windows 8中引入的Metro apps.(后来又被称作Modern apps, Windows apps, Universal Windows A ...

  4. bootStrap模态框与select2合用时input不能获取焦点、模态框内部滑动,select选中跳转

    bootStrap模态框与select2合用时input不能获取焦点 在bootstrap的模态框里使用select2插件,会导致select2里的input输入框没有办法获得焦点,没有办法输入. 把 ...

  5. Saruman's Army

    直线上有N个点. 点i的位置是Xi.从这N个点中选择若干个,给它们加上标记. 对每一个点,其距离为R以内的区域里必须有带有标记的点(自己本身带有标记的点, 可以认为与其距离为 0 的地方有一个带有标记 ...

  6. java包装类注意点

    Integer one = new Integer(100); Integer two = new Integer(100); Integer three = 100; Integer fore = ...

  7. 如何在 Go 中嵌入 Python

    如果你看一下 新的 Datadog Agent,你可能会注意到大部分代码库是用 Go 编写的,尽管我们用来收集指标的检查仍然是用 Python 编写的.这大概是因为 Datadog Agent 是一个 ...

  8. 地图控件:overview、scale、toolbar

    地图常用控件: 1.AMap.MapType:地图类型切换插件,用来切换固定的几个常用图层 2.AMap.OverView:地图鹰眼插件,默认在地图右下角显示缩略图 3.AMap.Scale:地图比例 ...

  9. LeetCode入门指南 之 回溯思想

    模板 result = {} void backtrack(选择列表, 路径) { if (满足结束条件) { result.add(路径) return } for 选择 in 选择列表 { 做选择 ...

  10. C# - 习题03_分析代码写出结果A.X、B.Y

    时间:2017-08-23 整理:byzqy 题目:分析代码,写出程序的输出结果: 文件:Program.cs 1 using System; 2 3 namespace Interview2 4 { ...