简体   繁体   English

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

[英]Python: How to mock SQLAlchemy event handlers (using mock.unittest)

So I have a SQLAlchemy model that has an event listener:所以我有一个具有事件侦听器的 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()

And I have a unit test that needs to update/insert the Model我有一个单元测试需要更新/插入模型

@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)

However, my tests fail because it seems like the do_something function is still being called and hasn't been mocked successfully.但是,我的测试失败了,因为似乎do_something函数仍在被调用并且尚未成功模拟。 I tried reading through how patching here (it is calling this function right?) and I have tried to look through the SQLAlchemy source code here to find the appropriate module to patch (something like @patch('sqlalchemy.event.registrat._listen_fn') ) but to no avail.我试图通过打补丁怎么读这里(这是调用这个函数吧?),我已经通过SQLAlchemy的源代码,想看看这里找到相应的模块补丁(像@patch('sqlalchemy.event.registrat._listen_fn') ) 但无济于事。

Has anyone ever encountered this before?有没有人遇到过这种情况?

Perhaps having a Context Manager class that removes the listener and add it again on exit could do the trick.也许有一个上下文管理器类可以删除侦听器并在退出时再次添加它可以解决问题。

Something like:就像是:

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_)

And then just use it:然后只需使用它:

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

I've found a workaround to disable events on unit tests我找到了一种解决方法来禁用单元测试中的事件

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM