使用 pytest 进行测试时,如何使用 >= 2 的工作人员干净地终止 Uvicorn + FastAPI 应用程序

2023-11-24

我有一个用 Uvicorn + FastAPI 编写的应用程序。 我正在使用 PyTest 测试响应时间。

参考使用 PyTest 进行测试时如何在后台启动 Uvicorn + FastAPI,我写了测试。 然而,当工人> = 2时,我在完成测试后发现应用程序进程处于活动状态。

我想在测试结束时干净地终止应用程序进程。

你有什么主意吗?

详情如下。

环境

  • Windows 10
  • 重击 4.4.23 (https://cmder.net/)
  • 蟒蛇3.7.5

图书馆

  • 快速 API == 0.68.0
  • 紫角兽 == 0.14.0
  • 请求==2.26.0
  • pytest==6.2.4

示例代码

  • 应用程序:main.py
    from fastapi import FastAPI
    
    app = FastAPI()
    
    @app.get("/")
    def hello_world():
        return "hello world"
    
  • 测试:test_main.py
    from multiprocessing import Process
    import pytest
    import requests
    import time
    import uvicorn
    
    HOST = "127.0.0.1"
    PORT = 8765
    WORKERS = 1
    
    
    def run_server(host: str, port: int, workers: int, wait: int = 15) -> Process:
        proc = Process(
            target=uvicorn.run,
            args=("main:app",),
            kwargs={
                "host": host,
                "port": port,
                "workers": workers,
            },
        )
        proc.start()
        time.sleep(wait)
        assert proc.is_alive()
        return proc
    
    
    def shutdown_server(proc: Process):
        proc.terminate()
        for _ in range(5):
            if proc.is_alive():
                time.sleep(5)
            else:
                return
        else:
            raise Exception("Process still alive")
    
    
    def check_response(host: str, port: int):
        assert requests.get(f"http://{host}:{port}").text == '"hello world"'
    
    
    def check_response_time(host: str, port: int, tol: float = 1e-2):
        s = time.time()
        requests.get(f"http://{host}:{port}")
        e = time.time()
        assert e-s < tol
    
    
    @pytest.fixture(scope="session")
    def server():
        proc = run_server(HOST, PORT, WORKERS)
        try:
            yield
        finally:
            shutdown_server(proc)
    
    
    def test_main(server):
        check_response(HOST, PORT)
        check_response_time(HOST, PORT)
        check_response(HOST, PORT)
        check_response_time(HOST, PORT)
    

执行结果

$ curl http://localhost:8765
curl: (7) Failed to connect to localhost port 8765: Connection refused
$ pytest test_main.py
=============== test session starts =============== platform win32 -- Python 3.7.5, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: .\
collected 1 item

test_main.py .                                                                                                                                                                                                                         [100%]

=============== 1 passed in 20.23s ===============
$ curl http://localhost:8765
curl: (7) Failed to connect to localhost port 8765: Connection refused
$ sed -i -e "s/WORKERS = 1/WORKERS = 3/g" test_main.py
$ curl http://localhost:8765
curl: (7) Failed to connect to localhost port 8765: Connection refused
$ pytest test_main.py
=============== test session starts =============== platform win32 -- Python 3.7.5, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: .\
collected 1 item

test_main.py .                                                                                                                                                                                                                         [100%]

=============== 1 passed in 20.21s ===============
$ curl http://localhost:8765
"hello world"

$ # Why is localhost:8765 still alive?

我自己找到了解决方案。

谢谢>https://stackoverflow.com/a/27034438/16567832

Solution

安装 psutil 后pip install psutil,更新test_main.py

from multiprocessing import Process
import psutil
import pytest
import requests
import time
import uvicorn

HOST = "127.0.0.1"
PORT = 8765
WORKERS = 3


def run_server(host: str, port: int, workers: int, wait: int = 15) -> Process:
    proc = Process(
        target=uvicorn.run,
        args=("main:app",),
        kwargs={
            "host": host,
            "port": port,
            "workers": workers,
        },
    )
    proc.start()
    time.sleep(wait)
    assert proc.is_alive()
    return proc


def shutdown_server(proc: Process):

    ##### SOLUTION #####
    pid = proc.pid
    parent = psutil.Process(pid)
    for child in parent.children(recursive=True):
        child.kill()
    ##### SOLUTION END ####

    proc.terminate()
    for _ in range(5):
        if proc.is_alive():
            time.sleep(5)
        else:
            return
    else:
        raise Exception("Process still alive")


def check_response(host: str, port: int):
    assert requests.get(f"http://{host}:{port}").text == '"hello world"'


def check_response_time(host: str, port: int, tol: float = 1e-2):
    s = time.time()
    requests.get(f"http://{host}:{port}")
    e = time.time()
    assert e-s < tol


@pytest.fixture(scope="session")
def server():
    proc = run_server(HOST, PORT, WORKERS)
    try:
        yield
    finally:
        shutdown_server(proc)


def test_main(server):
    check_response(HOST, PORT)
    check_response_time(HOST, PORT)
    check_response(HOST, PORT)
    check_response_time(HOST, PORT)

执行结果

$ curl http://localhost:8765
curl: (7) Failed to connect to localhost port 8765: Connection refused
$ pytest test_main.py
================== test session starts ================== platform win32 -- Python 3.7.5, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: .\
collected 1 item

test_main.py .                                                                                                                                                                                                                         [100%]

================== 1 passed in 20.24s ==================
$ curl http://localhost:8765
curl: (7) Failed to connect to localhost port 8765: Connection refused
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 pytest 进行测试时,如何使用 >= 2 的工作人员干净地终止 Uvicorn + FastAPI 应用程序 的相关文章

  • 与 iexact 一起使用时,Django get_or_create 无法设置字段

    我想用name iexact with get or create尽可能避免用户输入字段的重复 我的提供者模型有一个名称字段 我在其中使用get or create 查找工作正常 但在第一次创建实例时 如下面的 p1 Timber 示例 名
  • python导入模块时如何避免一直写模块名?

    我用math最近模块很多 我不想写math sqrt x and math sin x 每时每刻 我想缩短它并写sqrt x and sin x How 对于较长的模块名称 通常会缩短它们 例如 import numpy as np 然后您
  • DataFrame 在函数内部修改

    我面临一个我以前从未观察到的函数内数据帧修改的问题 有没有一种方法可以处理这个问题 以便初始数据帧不被修改 def test df df tt np nan return df dff pd DataFrame data 现在 当我打印时d
  • Python 中的安全解除引用

    Groovy 有一个很好的安全取消引用运算符 这有助于避免 NullPointerExceptions variable method The method仅当以下情况时才会被调用variable is not null 有没有办法在 Py
  • 为什么在 Windows 中使用 GetConsoleScreenBufferInfoEx 时控制台窗口会缩小?

    我正在尝试使用 GetConsoleScreenBufferInfoEx 和 SetConsoleScreenBufferInfoEx 设置 Windows 命令行控制台的背景和前景色 我正在 Python 中使用 wintypes 进行此
  • 将 API 数据存储到 DataFrame 中

    我正在运行 Python 脚本来从 Interactive Brokers API 收集金融市场数据 连接到API后 终端打印出请求的历史数据 如何将数据保存到数据帧中而不是在终端中流式传输 from ibapi wrapper impor
  • 如何从谷歌云存储桶读取音频文件并在datalab笔记本中使用ipd播放

    我想在数据实验室笔记本中播放我从谷歌云存储桶中读取的声音文件 这个怎么做 import numpy as np import IPython display as ipd import librosa import soundfile as
  • 如何在 ReportLab 段落中插入回车符?

    有没有办法在 ReportLab 的段落中插入回车符 我试图将 n 连接到我的段落字符串 但这不起作用 Title Paragraph Title n Page myStyle 我想要这样做 因为我将名称放入单元格中 并且想要控制单元格中的
  • 字典中的列表,Python 中的循环

    我有以下代码 TYPES hotmail type hotmail lookup mixed dkim no signatures S Return Path email protected cdn cgi l email protecti
  • 在Python中创建一个新表

    我正在尝试从数控机床中提取数据 事件每毫秒发生一次 我需要过滤掉一些用管道 分隔的变量分隔符 PuTTy exe 程序生成的日志文件 我尝试阅读熊猫 但列不在同一位置 df pd read table data log sep 日志文件的一
  • 如何修复错误“AttributeError:‘模块’对象在 python3 中没有属性‘客户端’?

    以下是我的代码 import http h1 http client HTTPConnection www bing com 我认为没问题 但是 python 给了我以下错误 AttributeError 模块 对象没有属性 客户端 我想知
  • 如何对这个 Flask 应用程序进行单元测试?

    我有一个 Flask 应用程序 它使用 Flask Restless 来提供 API 我刚刚写了一些身份验证来检查 如果消费者主机被识别 该请求包含一个哈希值 通过加密 POST 的请求内容和 GET 的 URL 以及秘密 API 密钥来计
  • 如何使用 PySpark 有效地将这么多 csv 文件(大约 130,000 个)合并到一个大型数据集中?

    我之前发布了这个问题并得到了一些使用 PySpark 的建议 如何有效地将这一大数据集合并到一个大数据框中 https stackoverflow com questions 60259271 how can i merge this la
  • pip 安装软件包两次

    不幸的是我无法重现它 但我们已经见过几次了 pip 将一个软件包安装两次 如果卸载第一个 第二个就会可见并且也可以被卸载 我的问题 如果一个包安装了两次 如何用 python 检查 背景 我想编写一个测试来检查这一点 devOp Updat
  • Python正则表达式从字符串中获取浮点数

    我正在使用正则表达式来解析字符串中的浮点数 re findall a zA Z d d t 是我使用的代码 这段代码有问题 如果数字和任何字符之间没有空格 则不会解析该数字 例如 0 1 2 3 4 5 6 7 8 9 的预期输出为 0 1
  • 参数验证,Python 中的最佳实践[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 让我们举一个 API 的例子 def get abs directory self path if os path isdir path ret
  • 为什么“return self”返回 None ? [复制]

    这个问题在这里已经有答案了 我正在尝试获取链的顶部节点getTopParent 当我打印出来时self name 它确实打印出了父实例的名称 然而 当我回来时self 它返回 None 为什么是这样 class A def init sel
  • 如何强制 Y 轴仅使用整数

    我正在使用 matplotlib pyplot 模块绘制直方图 我想知道如何强制 y 轴标签仅显示整数 例如 0 1 2 3 等 而不显示小数 例如 0 0 5 1 1 5 2 等 我正在查看指导说明并怀疑答案就在附近matplotlib
  • 大型数据集上的 Sklearn-GMM

    我有一个很大的数据集 我无法将整个数据放入内存中 我想在这个数据集上拟合 GMM 我可以用吗GMM fit sklearn mixture GMM 重复小批量数据 没有理由重复贴合 只需随机采样您认为机器可以在合理时间内计算的尽可能多的数据
  • Jupyter Notebook:没有名为 pandas 的模块

    我搜索了其他问题 但没有找到任何有帮助的内容 大多数只是建议您使用 conda 或 pip 安装 pandas 在我的 jupyter 笔记本中 我试图导入 pandas import pandas as pd 但我收到以下错误 Modul

随机推荐

  • 如何使用匹配节点连接两个 XML 文件

    我需要找到一种方法 当两个 XML 文件具有匹配的节点时将它们连接起来 据我所知 这可以用许多不同的语言来完成 是否有 PHP 或 AJAX 方法来做到这一点 从 SO 上的其他帖子中我看到了 XSLT 解决方案 但我并没有真正理解 这是最
  • .NET 从 HTML 页面中删除/剥离 JavaScript 和 CSS 代码块

    我有带有 JavaScript 和 CSS 代码块的 HTML 字符串 如何剥离这些块 关于可用于删除这些的正则表达式有什么建议吗 快速的 n 脏方法将是一个像这样的正则表达式
  • 如何使用 Javascript 对 HTML 文档进行永久更改?

    我有一个简单的计数器代码 但所做的更改消失了 页面刷新后 为什么会发生这种情况 应该使用 PHP 来完成吗 如何更有效地编写这段代码 无论如何 这不是主要问题 var like document getElementById like im
  • 在另一个页面中获取magento会话变量

    我在 magento 模式页面的会话中设置数组变量 并希望在另一个页面 如 getuserdata php 中检索 但不进入另一个页面 我设置变量并进入一页 然后完全检索 我的代码就像 首页代码 session Mage getSingle
  • 我们有 Perl 中的 autochomp 吗?

    这就是我的 Perl 代码的样子监控 Unix 文件夹 usr bin perl use strict use warnings use File Spec Functions my date date chomp date my date
  • XCode 5 中的配置文件

    我今天开始使用 XCode 5 并在尝试归档一个项目以进行临时分发时发现 我看到的配置文件不包括我最近创建的配置文件 但确实包括我已删除的配置文件 我检查了我的管理器中该设备的配置文件列表 该列表没问题 并且包含我最近下载的配置文件 所以我
  • c#:将网页的html源代码读取为字符串[重复]

    这个问题在这里已经有答案了 我希望能够使用 winforms 将某个网页的 html 源读入 C 中的字符串 我该怎么做呢 string html new WebClient DownloadString http twitter com
  • ASP.NET 主题样式表渲染

    当呈现具有主题的页面时 给定主题中的样式表链接标记将呈现在结束头标记之前 有谁知道有什么方法可以改变这种情况吗 有没有办法让我可以将这些标签放置在起始头标签之后 我知道它可以通过jquery关闭 只需选择所有链接标签并将其放置在起始头标签之
  • 如何在groovy中合并两个地图

    问题 如何合并映射 同时求和映射之间公共键的值 Input a 10 b 2 c 3 b 3 c 2 d 5 Output a 10 b 5 c 5 d 5 扩展问题 如何通过对 2 个映射中的公共键的值应用函数 闭包 来合并原始的 2 个
  • 解组时未找到类:android.support.v7.widget.Toolbar$SavedState

    我正在使用 Maps API 创建一个简单的 Android 应用程序 但出现了一个我无法解决的奇怪错误 当我旋转设备时通常会发生这种情况 我正在使用谷歌服务8 4 0 4 23 15 39 47 503 9419 9419 com lic
  • 在 Ubuntu C++ 上找不到 gtk/gtk.h

    我对编程相当陌生 尤其是在涉及如何包含库和类似活动时 我过去曾使用 Python 进行过一些编程 并且一直使用 GTK 来创建窗口 这也是我在使用 C 编程时打算做的事情 首先 这是我的代码 include
  • VsTac 任务失败,使用全局 Cordova 工具集时找不到文件 appAsTgz.tgz

    当我使用全局安装的 Cordova 7 1 0 工具集并执行 iOS 远程构建 到模拟器或本地设备 时 我几乎立即收到错误消息 Error MSB4018 The VsTac task failed unexpectedly System
  • 积分推广与运营商+=

    我需要消除 gcc Wconversion 警告 例如 typedef unsigned short uint16 t uint16 t a 1 uint16 t b 2 b a gives warning conversion to ui
  • 使用 JQuery 禁用链接

    我有以下代码 其功能类似于 Stackoverflow 上评论链接的工作方式 单击时 它会触发 ActionResult 并填充 div function a id doneLink live click function event ma
  • Chrome:播放通过 fetch/XHR 下载的视频

    我想要实现的是让 Chrome 将视频文件作为数据加载 通过 Fetch API XHR 等 并使用
  • Sigaction 并将 Linux 代码移植到 Windows

    我正在尝试移植caffe 针对Linux开发 源代码到Windows环境 问题在于sigaction结构在signal handler cpp and signal handler h 源代码如下所示 我的疑问是可以替换哪个库或代码来实现此
  • JSON 解析错误:未终止的字符串

    在 JSON 解析函数中转义引号时 我遇到了一个常见问题 如果存在转义引号 在本例中为 test 则会导致以下错误 SyntaxError JSON 解析错误 未终止的字符串 var information JSON parse 1 24
  • 仅回形针处理图像

    我想对多种格式使用单个文件字段 据我了解 Paperclip 足够智能 只能缩放图像并保留其他格式 但这似乎不适用于 flv 它返回 imagemagick identify errors 有没有什么方法可以帮助 Paperclip 并明确
  • Youtube 获取上传的视频列表。文件未找到错误

    我正在尝试使用以下方法获取在我的 YouTube 频道上上传的视频列表 MY CHANNEL ID maxResults 50 key MY APP ID 我已经在 Google App Console 中创建了应用程序并为其生成了 APP
  • 使用 pytest 进行测试时,如何使用 >= 2 的工作人员干净地终止 Uvicorn + FastAPI 应用程序

    我有一个用 Uvicorn FastAPI 编写的应用程序 我正在使用 PyTest 测试响应时间 参考使用 PyTest 进行测试时如何在后台启动 Uvicorn FastAPI 我写了测试 然而 当工人 gt 2时 我在完成测试后发现应