FastAPI 之自动化测试数据库接口

运维 数据库运维 自动化
今天的文章分享如下在 FastAPI 框架下,使用 pytest 来自动化测试数据库相关的接口,文章的最后给出全部代码。

[[442950]]

今天的文章分享如下在 FastAPI 框架下,使用 pytest 来自动化测试数据库相关的接口,文章的最后给出全部代码。

最近越来越喜欢使用 FastAPI 来写后端服务了,因为它是 Python 领域性能最好的 Web 框架,它专注于提供高性能的 Web API,其他方面并不限制你的手脚,可以随意使用你喜欢的三方库,这点类似于 Flask,可以量身定制你的后端架构,以满足自己的需求。

需要说明的是,后端服务基本是离不开关系型数据库的,我之前是使用 Django,Django 的 ORM 太优秀了,以至于我从 Django 转 FastAPI 有点很不适应。在 ORM 领域,可以说除了 Django 的 ORM,就是 SQLAlchemy 了。所以不用 Django,就必须会用 SQLAlchemy,要快速了解,看看廖雪峰的官方网站的使用 SQLAlchemy[1] 来快速入门。

FastAPI 涉及数据库的接口写起来并不难,跟着官方文档sql_databases[2],5 分钟,我们就可以生成关于数据库的增删改查的 Restful 风格的 API,难的是如何自动化的测试,

通常情况下,我们会使用 pytest 进行自动化单元测试,根据数据库的记录数来断言,但是,每测试一次,数据库中的记录就保存了下来,你下次测试时如果不手动清理,那测试仍然可能失败。

那怎么解决呢?

那就是利用数据库的回滚功能,会改变数据库记录的接口测试完成后让事务回滚,这样每次测试完成后,数据库的记录数是不变的,每次运行 pytest,数据库的记录数是不变的,这样就可以进行自动化测试。

要想实现这一点,我们需要借助于 pytest 的 fixture 功能。

pytest.fixture 是一个装饰器,用于声明函数是一个 fixture。如果测试函数的参数列表中包含 fixture 名,那么 pytest 会检测到,并在测试函数运行之前执行 fixture。

比如:

  1. import pytest 
  2.  
  3. @pytest.fixture() 
  4. def some_data(): 
  5.     return 42 
  6.  
  7. def test_some_data(some_data): 
  8.     assert some_data==42 

fixture 包含一个 scope 的可选参数,用于控制 fixture 执行配置和销毁逻辑的频率:

  • scope='function' 函数级别的 fixture 每个测试函数只运行一次。配置代码在测试用例运行之前运行,销毁代码在测试用例运行之后执行。function 是 fixture 参数的默认值。
  • scope='class' 类级别的 fixture 每个测试类只运行一次,不管测试类中有多少个类方法都可以共享这个 fixture
  • scope='module' 模块级别的 fixture 每个模块只运行一次,不管模块里有多少个测试函数,类方法或其他 fixture 都可以共享这个fixture
  • scope='session' 会话级别的 fixture 每次会话只运行一次。一次 pytest 会话中的所有测试函数、方法都可以共享这个 fixture

比如说让数据库回滚的,我们就可以写一个这样的 fixture:

  1. @pytest.fixture(scope="function"
  2. def db(db_engine): 
  3.     connection = db_engine.connect() 
  4.     # begin a non-ORM transaction 
  5.     connection.begin() 
  6.     # bind an individual Session to the connection 
  7.     db = Session(bind=connection
  8.     # db = Session(db_engine) 
  9.     app.dependency_overrides[get_db] = lambda: db 
  10.     yield db 
  11.     db.rollback() 
  12.     connection.close() 

当然还有很多 fixture,比如说创建数据库引擎:

  1. @pytest.fixture(scope="session"
  2. def db_engine(): 
  3.     engine = create_engine(SQLALCHEMY_DATABASE_URL) 
  4.     if not database_exists: 
  5.         create_database(engine.url) 
  6.  
  7.     Base.metadata.create_all(bind=engine) 
  8.     yield engine 

再比如,在测试前,数据库中先插入 2 条数据:

  1. @pytest.fixture 
  2. def items(db): 
  3.     create_item(db, schemas.ItemCreate(title="item 1")) 
  4.     create_item(db, schemas.ItemCreate(title="item 2")) 

把这些 fixture 函数放在文件名conftest.py 中,pytest 会自动读取并执行。至于为什么放在 conftest.py中,请查阅 pytest 文档,这里不展开,

接下来,利用这些 fixture,编写单元测试用例,一个示例如下:

  1. from fastapi.testclient import TestClient 
  2. from . import crud 
  3. from .main import app 
  4.  
  5. def test_post_items(db): 
  6.     client = TestClient(app) 
  7.     client.post("/items/", json={"title""Item 1"}) 
  8.     client.post("/items/", json={"title""Item 2"}) 
  9.     client.post("/items/", json={"title""Item 3"}) 
  10.  
  11.     items = crud.get_items(db) 
  12.     assert len(items) == 3 
  13.  
  14.  
  15. def test_list_items(items, client): 
  16.     response = client.get("/items"
  17.     assert len(response.json()) == 2 

其中 test_post_items,测试的是提交了 3 个数据,然后断言数据库中的记录数为 3。test_list_items 有个参数是 items,会调用之前的 fixture,提前往数据库插入了 2 条记录,因此断言记录数为 2。

每个测试函数执行时互不影响,执行完成后,数据库都会回滚,测试前 items 是空的,测试之后 表仍然是空的,这样就可以自动进行数据库的测试了。

完整代码

不能选择 sqlite 数据库进行测试,因为它不支持并发访问。

 

代码的数据库配置为 mysql,用户名、密码、数据库名请自行修改后执行。

 

责任编辑:武晓燕 来源: Python七号
相关推荐

2013-06-07 19:04:15

测试

2018-05-11 13:39:05

PythonCSV接口测试

2018-05-11 08:29:10

Python自动化测试数据驱动

2017-01-17 15:14:49

MySQL数据库自动化

2023-05-18 14:01:00

前端自动化测试

2011-04-01 15:07:29

数据库自动化

2022-12-26 12:30:28

接口测试

2023-09-13 11:40:12

2014-04-16 14:15:01

QCon2014

2022-02-17 10:37:16

自动化开发团队预测

2010-12-21 13:13:10

BMC数据库自动化服务

2013-05-16 10:58:44

Android开发自动化测试

2012-02-27 17:34:12

Facebook自动化

2021-09-03 09:56:18

鸿蒙HarmonyOS应用

2012-12-24 22:54:31

2021-06-30 19:48:21

前端自动化测试Vue 应用

2011-12-23 17:09:57

自动化测试

2024-11-01 15:05:12

2022-08-14 16:11:23

Python自动化测试数据

2016-09-23 09:22:12

点赞
收藏

51CTO技术栈公众号