首页 > 编程问答 >Flask API Pytest 单元测试由于 Pyodbc 失败

Flask API Pytest 单元测试由于 Pyodbc 失败

时间:2024-07-24 05:14:12浏览次数:13  
标签:python flask pytest

我在使用 Pytest 时遇到一些问题。我的 Flask API 使用 pyodbc 与 MSSQL 服务器数据库对话。该 API 在 Docker 容器中运行,我在 Mac 上运行它。

我有一个健康检查(根级别即 localhost:5000/ )路由的单元测试,如下所示:

from app import app

def test_healthcheck(self):
    """
    Test the healthcheck endpoint
    EXPECTS: A 200 status code and the string "Healthcheck"
    """
    with app.test_client() as test_client:
        response = self.app.get("/")
        assert response.status_code == 200
        assert response.data, b"Healthcheck"

我的项目是结构化的如下:

myproject
| app.py
| — api/
       | — routes/
       | — utils/
                | db.py
                | helpers.py

| — tests/
         | test_healthcheck.py

当我运行 python3 -m pytest 时,出现以下错误:

ERROR tests/test_healthcheck.py - pyodbc.Error: ('01000', "[01000] [unixODBC][Driver Manager]Can't open lib 'ODBC Driver 18 for SQL Server' : file not found (0) (SQLDriverConnect)")

错误日志显示pyodbc错误源于 pyodbc.connect() 行我的db.py util文件,这是一个基于类的抽象数据库操作的。

class DB:
    """
    Class to abstract out MS SQL Server DB operations
    """

    def __init__(self):
        self.conn_str = os.getenv("CONN_STR")
        if not self.conn_str:
            raise RuntimeError("Missing 'CONN_STR' env var")
        self.conn = pyodbc.connect(self.conn_str)

但是我在本地计算机上安装了 pyodbc,当我在 Docker 中运行 API 时,我没有遇到任何 pyodbc 问题。

如果这有帮助,app.py 如下:

import logging
from flask import Flask
from dotenv import load_dotenv

from api.routes.healthcheck import bp as health_bp
from api.routes.generate import bp as generate_bp

load_dotenv()

app = Flask(__name__)
app.register_blueprint(health_bp)
app.register_blueprint(generate_bp)

logging.basicConfig(level=logging.INFO)
logging.getLogger("werkzeug").setLevel(logging.INFO)

我看到 Pytest 文档谈论 conftest.py 文件,但这似乎依赖于工厂应用程序模式,而该应用程序则不然。我需要比赛吗?我该如何消除这个 pyodbc 错误?


问题在于 Pytest 在运行测试时,是在独立的进程中运行,而不是在 Docker 容器内。因此,它找不到 Docker 容器中安装的 ODBC 驱动和配置。

解决这个问题有几种方法:

1. 使用 Docker Compose 运行测试:

这是最干净和最推荐的方法。 你可以使用 Docker Compose 来启动一个包含你的应用程序和依赖项的测试环境,并在该环境中运行 Pytest。

  • 在你的项目根目录创建一个 docker-compose.test.yml 文件:
version: '3.8'
services:
  api:
    build: .
    command: python3 -m pytest
    volumes:
      - .:/app:ro
    environment:
      - CONN_STR=YOUR_TEST_CONN_STR
  • YOUR_TEST_CONN_STR 替换为你的测试数据库连接字符串。
  • 运行 docker-compose -f docker-compose.test.yml up 来启动测试环境并运行测试。

2. 模拟数据库连接:

你可以使用 unittest.mock pytest-mock 库来模拟 pyodbc.connect 函数,并返回一个模拟的数据库连接对象。 这种方法不需要安装 ODBC 驱动,但你需要修改测试代码以使用模拟的连接。

  • 安装 pytest-mock : pip install pytest-mock
  • 修改测试代码:
from unittest.mock import MagicMock

# ...

def test_healthcheck(mocker):
    """Test the healthcheck endpoint"""
    mock_conn = MagicMock()
    mocker.patch('pyodbc.connect', return_value=mock_conn)

    with app.test_client() as test_client:
        response = test_client.get("/")
        assert response.status_code == 200
        assert response.data == b"Healthcheck"

3. 在测试环境中安装 ODBC 驱动:

你可以尝试在你的本地环境中安装与 Docker 容器相同的 ODBC 驱动和配置。 但是,这种方法容易出错,并且在不同的环境中可能难以维护。

建议使用第一种方法,因为它可以提供一个更可靠和可重复的测试环境。

标签:python,flask,pytest
From: 78785596

相关文章

  • 如何使用 Python 打开 Google Firestore 上的特定数据库?
    我正在使用Firebase并使用以下代码从Firestore设置/检索文档:importfirebase_adminfromfirebase_adminimportcredentials,firestorecred=credentials.ApplicationDefault()firebase_admin.initialize_app(cred,options={"projectId":"huq-jimbo"})fires......
  • 如何使用 Python 和 Numpy 重现 Matlab 文件读取以解码 .dat 文件?
    我有一个Matlab脚本,可以读取编码的.dat文件,对其进行解码并保存。我试图使用numpy将其转换为Python。我发现对于同一个文件,我得到不同的输出结果(python数字没有意义)。该代码最初作为从串行端口读取的脚本的一部分运行,因此是数据的结构。我首先认为位移是问题所在,因为......
  • 在Python中调整pdf页面大小
    我正在使用python裁剪pdf页面。一切正常,但如何更改页面大小(宽度)?这是我的裁剪代码:input=PdfFileReader(file('my.pdf','rb'))p=input.getPage(1)(w,h)=p.mediaBox.upperRightp.mediaBox.upperRight=(w/4,h)output.addPage(p)当我裁剪页面时,我也需要......
  • 如何使用 python 更改资源管理器窗口中的路径?
    没有人知道如何在不使用python打开新实例的情况下更改资源管理器窗口中的当前路径吗?例如,如果用户使用C:\Users\User打开资源管理器窗口。然后我必须将该路径更改为C:\Windows\System32例如。提前致谢。很遗憾,无法直接使用Python更改现有文件资源管理器窗口的......
  • python 以及将数组传递给函数的问题
    我需要求解一些常微分方程$\frac{dy}{dx}=f(x)=x^2ln(x)$并继续在限制0之间创建数组xpt。<=xpt<=2因为我必须小心xpt=0,所以我将函数定义如下deff(x):ifx<=1.e-6:return0.else:returnnp.square(x)*np.log(x)我的调用程序读取Np......
  • 如果 Python 脚本正在使用文件夹,如何在文件资源管理器中进行更改时防止 Windows 的“
    我有一个简单的脚本,显示在QTreeView中的QListView中选择的目录的内容,我想添加打开文件资源管理器的功能,以让用户编辑目录内的内容。但是,添加新的文件夹和文件可以,但删除或移动文件夹或文件会提示“文件夹正在使用”错误:此操作无法完成,因为该文件已在另一个程......
  • 如何使用 Python API 获取每个模型的活跃用户列表、最后登录信息
    我想通过PythonAPI获取我的dbt项目的所有模型中的活动或非活动用户列表。这可能吗?我尝试列出模型,但无法获取用户信息,如用户名、项目、以及上次活动或上次登录。不幸的是,dbt本身并不跟踪你所寻找的用户活动数据(最后登录、活跃用户等)。dbt的主要功能是转换数据,而不......
  • Python tkinter 窗口不断关闭,我不知道为什么
    我正在尝试制作一个有趣的小程序,其中每小时左右就会有一只毛茸茸的动物走过屏幕。我有一个主窗口,它启动一个循环,每小时左右播放一次动画/声音,但是在口袋妖怪第一次完成行走后,整个程序就会结束。我认为这可能与我设置tkinter窗口的方式有关,但我无法弄清楚。我认为在这里包含......
  • 用于自动访问 MongoDB Atlas CLI 的 Python 脚本
    我想编写一个Python脚本,以便普通用户可以访问他的数据库并从他的终端执行CRUD操作。我正在查看官方文档,但我有点迷失。有人可以给我指点基本教程来开始吗?当然,以下是如何构建Python脚本来访问MongoDBAtlasCLI的基本教程:先决条件:MongoDBAtlas......
  • Python实现简单学生登陆系统
     代码:importhashlibclassStudent:def__init__(self,username,password):#初始化学生对象,存储用户名和加密后的密码self.username=usernameself.password=hashlib.sha256(password.encode()).hexdigest()defcheck_passwo......