Python:如何使用mock.unittest模拟SQLAlchemy事件处理程序

4

我有一个SQLAlchemy模型,其中包含一个事件监听器:

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)

@event.listens_for(User, "after_insert")
@event.listens_for(User, "after_update")
def do_something(mapper, connection, self):
    foo = SomeClass(self)
    foo.do_something_to_database()

我有一个单元测试需要更新/插入模型。

@patch('my_package.user.do_something')
def test_user(mock_do_something):
    user = User() # This insert will invoke 'do_something' via the event listener.
    assertSomething(user)

然而,我的测试失败了,因为似乎do_something函数仍在被调用,并且没有成功地进行模拟。我尝试阅读如何修补这里(它正在调用这个函数吗?),并且我已经尝试查看SQLAlchemy源代码这里来找到适当的模块进行修补(例如@patch('sqlalchemy.event.registrat._listen_fn')),但是都没有成功。

有人遇到过这种情况吗?

2个回答

3
也许有一个上下文管理器类来删除侦听器并在退出时再次添加侦听器可以解决问题。
像这样的东西:
class SADeListener(object):
    def __init__(self, class_, event, callable_):
        self.class_ = class_
        self.event = event
        self.callable_ = callable_

    def __enter__(self):
        sqlalchemy.event.remove(self.class_, self.event, self.callable_)

    def __exit__(self, type_, value, tb):
        sqlalchemy.event.listen(self.class_, self.event, self.callable_)

然后只需使用它:

with SADeListener(User, "after_insert", do_something),
   SADeListener(User, "after_update", do_something):
    .. code ...

1

我找到了一种解决方案来禁用单元测试中的事件

import sqlalchemy as sa
from unittest import TestCase
from mypackage.models.user import User

class TestUser(TestCase):
    def setUp(self):
        super(TestUser, self).setUp()
        sa.event.remove(User, "after_insert", do_something)
        sa.event.remove(User, "after_update", do_something)

    def tearDown(self):
        super(TestUser, self).tearDown()
        sa.event.listen(User, "after_insert", do_something)
        sa.event.listen(User, "after_update", do_something)

    @patch('my_package.user.do_something')
    def test_user(mock_do_something):
        user = User() 
        assertSomething(user)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接