【问题标题】:How can I use pytest monkeypatch to mock calls to SQLAlchemy create_engine call如何使用 pytest monkeypatch 模拟对 SQLAlchemy create_engine 调用的调用
【发布时间】:2022-07-04 22:32:14
【问题描述】:

我有一个返回 SQLAlchemy 引擎对象的函数

create_db.py:

from sqlalchemy import create_engine


def init_db():
    return create_engine("sqlite://", echo=True, future=True)

我有一个测试试图使用 pytest 的 monkeypatch 来模拟对 create_engine 的调用。

test_db.py:

import sqlalchemy
from create_db import init_db


def test_correct_db_path_selected(monkeypatch):
    def mocked_create_engine():
        return "test_connection_string"

    monkeypatch.setattr(sqlalchemy, "create_engine", mocked_create_engine())
    engine = init_db()
    assert engine == "test_connection_string"

当我运行 pytest 时,测试失败,因为返回的是真正的 sqlalchemy 引擎对象,而不是模拟的字符串。

AssertionError: assert Engine(sqlite://) == 'test_connection_string'

我尝试了以下对 setattr 的调用,但它们都以相同的方式失败:

    monkeypatch.setattr("sqlalchemy.engine.create.create_engine", mocked_create_engine)
    monkeypatch.setattr(sqlalchemy.engine.create, "create_engine", mocked_create_engine)
    monkeypatch.setattr(sqlalchemy.engine, "create_engine", mocked_create_engine)

我已经从 pytest 文档中获得了 basic examples,但它不包括库中的静态函数。有人对我做错了什么有任何建议吗?

【问题讨论】:

    标签: python sqlalchemy pytest monkeypatching


    【解决方案1】:

    所以我找到了解决问题的方法,但我仍然不清楚为什么上面的代码不起作用。

    如果我将我的 create_db.py 更改为直接调用 sqlalchemy.create_engine,则模拟函数起作用。

    create_db.py:

    import sqlalchemy
    
    
    def init_db():
        return sqlalchemy.create_engine("sqlite://")
    

    test_db.py:

    import sqlalchemy
    from create_db import init_db
    
    class MockEngine:
        def __init__(self, path):
            self.path = path
    
    def test_correct_db_path_selected(monkeypatch):
        def mocked_create_engine(path):
            return MockEngine(path=path)
    
        monkeypatch.setattr(sqlalchemy, "create_engine", mocked_create_engine)
        engine = init_db()
        assert engine.path == "sqlite://"
    

    我不介意更改我的代码以使其更具可测试性,但我仍然想知道是否可以模拟对原始 create_engine 调用的调用。我会留下问题并回答,以防其他人遇到同样的问题。

    编辑: 我找到了一个不涉及更改要测试的代码的解决方案。以下对 setattr 的调用将模拟不在对象上的函数调用:

    monkeypatch.setattr(create_db, "create_engine", mocked_create_engine)
    

    这是因为它告诉 monkeypatch 在 create_db.py 文件中模拟对 create_engine 的直接调用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-30
      • 1970-01-01
      • 2017-11-23
      • 2023-01-03
      • 1970-01-01
      • 2021-03-11
      • 2020-12-28
      相关资源
      最近更新 更多